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
4 changes: 2 additions & 2 deletions calphy/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,15 @@ def write_data(lmp, file):


def prepare_log(file, screen=False):
logger = logging.getLogger(__name__)
logger = logging.getLogger(file)

# Remove all existing handlers to prevent duplicate logging
for handler in logger.handlers[:]:
handler.close()
logger.removeHandler(handler)

handler = logging.FileHandler(file)
formatter = logging.Formatter("%(asctime)s %(name)-12s %(levelname)-8s %(message)s")
formatter = logging.Formatter("%(asctime)s calphy.helpers %(levelname)-8s %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
Expand Down
6 changes: 6 additions & 0 deletions calphy/routines.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ def run_jobs(self):
simfolder=self.calculations[1].create_folders(),
)

# Propagate MeltingTemp file handlers to sub-job loggers so that
# all sub-job output also appears in melting_temperature.log
for handler in self.logger.handlers:
self.soljob.logger.addHandler(handler)
self.lqdjob.logger.addHandler(handler)

self.logger.info(
"Free energy of %s and %s phases will be calculated"
% (self.soljob.calc.lattice, self.lqdjob.calc.lattice)
Expand Down
48 changes: 47 additions & 1 deletion tests/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import pytest
import tempfile
import os
import calphy.helpers as ch
import numpy as np

Expand Down Expand Up @@ -35,6 +37,50 @@ def test_validate_spring_constants():
e = ch.validate_spring_constants(d)
assert e[0] == 1

d = [1, np.NaN, 4]
d = [1, np.nan, 4]
e = ch.validate_spring_constants(d)
assert e[1] == 1

def test_prepare_log_no_handler_accumulation():
"""
Calling prepare_log twice for the same file should not accumulate handlers.
Each call should reset to exactly one file handler.
"""
with tempfile.TemporaryDirectory() as tmpdir:
logfile = os.path.join(tmpdir, "test.log")

logger1 = ch.prepare_log(logfile)
assert len(logger1.handlers) == 1, "Should have exactly 1 handler after first call"

logger2 = ch.prepare_log(logfile)
assert len(logger2.handlers) == 1, "Should still have exactly 1 handler after second call"
assert logger1 is logger2, "Should return the same logger object"

def test_prepare_log_no_cross_contamination():
"""
Two independent calculations logging to different files must not
write into each other's log files.
"""
with tempfile.TemporaryDirectory() as tmpdir:
log1 = os.path.join(tmpdir, "calc1.log")
log2 = os.path.join(tmpdir, "calc2.log")

logger1 = ch.prepare_log(log1)
logger1.info("message from calc1")

logger2 = ch.prepare_log(log2)
logger2.info("message from calc2")

# Flush all handlers
for h in logger1.handlers:
h.flush()
for h in logger2.handlers:
h.flush()

content1 = open(log1).read()
content2 = open(log2).read()

assert "message from calc1" in content1, "calc1.log should contain calc1 message"
assert "message from calc2" not in content1, "calc1.log must NOT contain calc2 message"
assert "message from calc2" in content2, "calc2.log should contain calc2 message"
assert "message from calc1" not in content2, "calc2.log must NOT contain calc1 message"
Loading