Skip to content

Commit 1c9c76e

Browse files
authored
Merge pull request #219 from keyurrmaniya/fix/melting-log
fix: use unique logger name per job to prevent log handler conflicts
2 parents 1acf990 + b3fe426 commit 1c9c76e

3 files changed

Lines changed: 55 additions & 3 deletions

File tree

calphy/helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,15 +232,15 @@ def write_data(lmp, file):
232232

233233

234234
def prepare_log(file, screen=False):
235-
logger = logging.getLogger(__name__)
235+
logger = logging.getLogger(file)
236236

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

242242
handler = logging.FileHandler(file)
243-
formatter = logging.Formatter("%(asctime)s %(name)-12s %(levelname)-8s %(message)s")
243+
formatter = logging.Formatter("%(asctime)s calphy.helpers %(levelname)-8s %(message)s")
244244
handler.setFormatter(formatter)
245245
logger.addHandler(handler)
246246
logger.setLevel(logging.DEBUG)

calphy/routines.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ def run_jobs(self):
168168
simfolder=self.calculations[1].create_folders(),
169169
)
170170

171+
# Propagate MeltingTemp file handlers to sub-job loggers so that
172+
# all sub-job output also appears in melting_temperature.log
173+
for handler in self.logger.handlers:
174+
self.soljob.logger.addHandler(handler)
175+
self.lqdjob.logger.addHandler(handler)
176+
171177
self.logger.info(
172178
"Free energy of %s and %s phases will be calculated"
173179
% (self.soljob.calc.lattice, self.lqdjob.calc.lattice)

tests/test_helpers.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import pytest
2+
import tempfile
3+
import os
24
import calphy.helpers as ch
35
import numpy as np
46

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

38-
d = [1, np.NaN, 4]
40+
d = [1, np.nan, 4]
3941
e = ch.validate_spring_constants(d)
4042
assert e[1] == 1
43+
44+
def test_prepare_log_no_handler_accumulation():
45+
"""
46+
Calling prepare_log twice for the same file should not accumulate handlers.
47+
Each call should reset to exactly one file handler.
48+
"""
49+
with tempfile.TemporaryDirectory() as tmpdir:
50+
logfile = os.path.join(tmpdir, "test.log")
51+
52+
logger1 = ch.prepare_log(logfile)
53+
assert len(logger1.handlers) == 1, "Should have exactly 1 handler after first call"
54+
55+
logger2 = ch.prepare_log(logfile)
56+
assert len(logger2.handlers) == 1, "Should still have exactly 1 handler after second call"
57+
assert logger1 is logger2, "Should return the same logger object"
58+
59+
def test_prepare_log_no_cross_contamination():
60+
"""
61+
Two independent calculations logging to different files must not
62+
write into each other's log files.
63+
"""
64+
with tempfile.TemporaryDirectory() as tmpdir:
65+
log1 = os.path.join(tmpdir, "calc1.log")
66+
log2 = os.path.join(tmpdir, "calc2.log")
67+
68+
logger1 = ch.prepare_log(log1)
69+
logger1.info("message from calc1")
70+
71+
logger2 = ch.prepare_log(log2)
72+
logger2.info("message from calc2")
73+
74+
# Flush all handlers
75+
for h in logger1.handlers:
76+
h.flush()
77+
for h in logger2.handlers:
78+
h.flush()
79+
80+
content1 = open(log1).read()
81+
content2 = open(log2).read()
82+
83+
assert "message from calc1" in content1, "calc1.log should contain calc1 message"
84+
assert "message from calc2" not in content1, "calc1.log must NOT contain calc2 message"
85+
assert "message from calc2" in content2, "calc2.log should contain calc2 message"
86+
assert "message from calc1" not in content2, "calc2.log must NOT contain calc1 message"

0 commit comments

Comments
 (0)