Skip to content
Draft
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
33a8005
intial pseudocode
jauy123 Apr 23, 2026
1bf0ee1
inital thought code (hadn't run it yet)
jauy123 Apr 23, 2026
24a6c31
more comments
jauy123 Apr 23, 2026
7a5c0b3
general cleanup
jauy123 Apr 23, 2026
f1be0df
Post black
jauy123 Apr 23, 2026
dbcfb1c
removed loop based control
jauy123 Apr 23, 2026
93966fb
Added formatter to handler
jauy123 Apr 23, 2026
c5f6133
Added format to start_logging() to replicate old behavior
jauy123 Apr 23, 2026
e30d0ab
Applied flake8
jauy123 Apr 23, 2026
5a5906d
notes for test later
jauy123 Apr 23, 2026
f679251
fix linter
jauy123 Apr 23, 2026
2ba1c2e
put logger back to start_logging()
jauy123 Apr 24, 2026
cca9258
cleaned up create()
jauy123 Apr 24, 2026
94f056f
removed MDAnalysis NullHandler
jauy123 Apr 24, 2026
7f5812f
readded top level import -- it broke some tests
jauy123 Apr 24, 2026
ba9315e
ported over tests
jauy123 Apr 24, 2026
0e36231
Used black
jauy123 Apr 24, 2026
e63f5ef
Added Tests for start_logging() and stop_logging()
jauy123 Apr 24, 2026
a81e4ad
Added comment
jauy123 Apr 24, 2026
f25aec7
Added comment
jauy123 Apr 24, 2026
bdaf241
post black
jauy123 Apr 24, 2026
ab00172
Merge branch 'logging' of github.com:jauy123/mdanalysis into logging
jauy123 Apr 24, 2026
d0b732f
Added comments about deprecations
jauy123 Apr 24, 2026
ec0ed25
Replaced logging.getLogger(MDAnalysis) with logging.getLogger(__name__)
jauy123 Apr 24, 2026
6d1a675
refined comments
jauy123 Apr 24, 2026
74bcc03
Updated tests
jauy123 Apr 24, 2026
0fdd02e
Change __name__ to MDAnalysis fix tests
jauy123 Apr 24, 2026
d952902
Updated Tests
jauy123 Apr 24, 2026
c34eca5
Added future tests
jauy123 Apr 24, 2026
f9a4961
Finished tests for mda.start_logging() and mda.stop_logging()
jauy123 May 1, 2026
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
58 changes: 36 additions & 22 deletions package/MDAnalysis/lib/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,30 @@
"""
import sys
import logging
import re
import os

from tqdm.auto import tqdm

from .. import version


def start_logging(logfile="MDAnalysis.log", version=version.__version__):
def start_logging(stream="MDAnalysis.log", version=version.__version__):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Under semantic versioning, you need to maintain backwards compatibility. So something like

def start_logging(stream="MDAnalysis.log", logfile=None, version=version.__version__):
  if logfile is not None:
     warnings.warn(DeprecationWarning, "logfile kwarg will be removed in MDAnalysis 3.0.0, use stream instead"
     # we probably have a dedicated function for the deprecation warning...
     stream = logfile
  ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

See my comment above in line 101. Why would a user want to manually change the version in this function? The version keyword should be deprecated and removed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That's fair. (I think this was a pattern where we wanted to avoid accessing global scope inside functions and passed the values through kwargs.)

"""Start logging of messages to file and console.

The default logfile is named `MDAnalysis.log` and messages are
logged with the tag *MDAnalysis*.
"""
create("MDAnalysis", logfile=logfile)
logging.getLogger("MDAnalysis").info(
Comment thread
jauy123 marked this conversation as resolved.
"MDAnalysis %s STARTED logging to %r", version, logfile
create(
"MDAnalysis",
stream=stream,
level="DEBUG",
fmt="%(asctime)s %(name)-12s %(levelname)-8s %(message)s",
)
create(
"MDAnalysis",
stream=sys.stdout,
level="INFO",
fmt="%(name)-12s: %(levelname)-8s %(message)s",
)
Comment on lines +110 to +121
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

All of this is intend to replicate old behavior from the original.



Expand All @@ -112,7 +120,9 @@ def stop_logging():
clear_handlers(logger) # this _should_ do the job...


Copy link
Copy Markdown
Contributor Author

@jauy123 jauy123 Apr 23, 2026

Choose a reason for hiding this comment

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

In general, I guess this PR make create() a more general type of function which add handlers to a master logger, so should it get renamed?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Probably yes to renaming, but you'd need to

  1. deprecate the old function
  2. schedule for removal in 3.0.0

because we're following semantic versioning https://semver.org and we cannot remove documented functionality in a public function until we make a new major release.

Similarly, we cannot just rename kwargs in a public function like create(). You have to keep the old one around and deprecated them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Probably should raise an issue of it as well

def create(logger_name="MDAnalysis", logfile="MDAnalysis.log"):
def create(
logger_name="MDAnalysis", stream="MDAnalysis.log", level="DEBUG", fmt=None
Comment thread
jauy123 marked this conversation as resolved.
Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

as above, you need to deprecate kwargs if you really want to rename them

):
"""Create a top level logger.

- The file logger logs everything (including DEBUG).
Expand All @@ -132,23 +142,27 @@ def create(logger_name="MDAnalysis", logfile="MDAnalysis.log"):

logger = logging.getLogger(logger_name)

logger.setLevel(logging.DEBUG)
logger.setLevel(level.upper())

# handler that writes to logfile
logfile_handler = logging.FileHandler(logfile)
logfile_formatter = logging.Formatter(
"%(asctime)s %(name)-12s %(levelname)-8s %(message)s"
)
logfile_handler.setFormatter(logfile_formatter)
logger.addHandler(logfile_handler)

# define a Handler which writes INFO messages or higher to the sys.stderr
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# set a format which is simpler for console use
formatter = logging.Formatter("%(name)-12s: %(levelname)-8s %(message)s")
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# https://docs.python.org/3/library/logging.handlers.html#streamhandler
#
# The StreamHandler class, located in the core logging package,
Comment thread
jauy123 marked this conversation as resolved.
Outdated
# sends logging output to streams such as sys.stdout, sys.stderr or
# any file-like object (or, more precisely, any object which supports
# write() and flush() methods).

# This only check the existance and not the functionality. Should be ok?
if hasattr(stream, "write") and hasattr(stream, "flush"):
handler = logging.StreamHandler(stream)
elif isinstance(stream, (str, os.PathLike)):
handler = logging.FileHandler(stream)
else:
raise TypeError("Input Stream is neither a file or a stream")

handler.setFormatter(logging.Formatter(fmt))
logger.addHandler(handler)

logger.info(f"MDAnalysis {version} STARTED logging to {stream!r}")
Comment thread
jauy123 marked this conversation as resolved.
Outdated

return logger

Expand Down
4 changes: 4 additions & 0 deletions testsuite/MDAnalysisTests/utils/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def test_start_stop_logging():
MDAnalysis.log.stop_logging()


# Write Tests here for later
# Idk why there are two seperate tests files: lib/test_log.py and utils/test_log.py
Comment thread
jauy123 marked this conversation as resolved.
Outdated


class RedirectedStderr(object):
"""Temporarily replaces sys.stderr with *stream*.

Expand Down
Loading