Skip to content

Logger: Python API - #1593

Open
nitbharambe wants to merge 12 commits into
mainfrom
pgm/feature/logger-python-api-implementation
Open

nitbharambe wants to merge 12 commits into
mainfrom
pgm/feature/logger-python-api-implementation

Conversation

@nitbharambe

@nitbharambe nitbharambe commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Summary of Python API of logger

Public import: from power_grid_model import Logger, LoggerType, both exported from the package root in __init__.py.

class Logger:
    def __init__(
        self,
        logger_type: LoggerType = LoggerType.info,
        *,
        python_logger: logging.Logger | None = None,
        level: int = logging.DEBUG,
    ) -> None: ...

    def __enter__(self) -> Logger: ...
    def __exit__(self, *_: object) -> None: ...

    @property
    def output(self) -> str: ...

    def clear(self) -> None: ...

LoggerType currently has one member: LoggerType.info = 3 (enum.py). (Benchmark to be added when #1598 is available)

Use Logger as a context manager to register it for calculations and unregister it on exit. output returns the accumulated text; clear() empties it. If python_logger is supplied, each non-empty output line is sent at the configured level on exit, then the buffer is cleared. The implementation and detailed behavior are in logger.py.

@nitbharambe
nitbharambe added this pull request to stack #1592 September 18, 2026 14:47
@nitbharambe nitbharambe changed the title input from poc Logger: Python API Sep 21, 2026
@mgovers
mgovers force-pushed the pgm/feature/logger-python-api-implementation branch 2 times, most recently from ee1b59e to 468e367 Compare September 24, 2026 11:59
@nitbharambe
nitbharambe marked this pull request as ready for review September 25, 2026 14:25
Comment on lines +300 to +311
class LoggerType(IntEnum):
"""Logger types for opt-in diagnostic output from calculations.

Output is non-conclusive and intended as debugging hints for advanced users.
"""

do_nothing = 0
"""Logger that discards all output (no-op). Useful as a typed placeholder."""
text = 1
"""Logger that captures timestamped text messages, including sparse-matrix hints."""
benchmark = 2
"""Logger that captures timing information per calculation phase."""

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.

let's follow the same conventions as for the C API

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.

This looks different from the C side enum PGM_LoggerType. Is that intentional?

@nitbharambe nitbharambe Sep 29, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@Jerry-Jinfeng-Guo Naming you mean? Renamed to info and then will add benchmark later.

Comment thread src/power_grid_model/_core/logger.py Outdated
Comment thread src/power_grid_model/_core/logger.py Outdated
self._active: bool = False

def __del__(self) -> None:
if self._active:

@mgovers mgovers Sep 28, 2026 •

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.

should be mutex'ed (or at least be atomic)

Comment thread src/power_grid_model/_core/logger.py Outdated
def __enter__(self) -> "Logger":
get_pgc().register_logger(self._logger_ptr)
assert_no_error()
self._active = True

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.

self._active must be atomic

Comment thread src/power_grid_model/_core/logger.py Outdated
assert_no_error()
self._python_logger = python_logger
self._level = level
self._active: bool = False

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.

must be atomic. Also refer to python/cpython#124366

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Did the suggested way in the link.

Comment thread src/power_grid_model/_core/logger.py Outdated
get_pgc().logger_clear(self._logger_ptr)
assert_no_error()

def flush_to_python_logger(self) -> None:

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.

in the future, we will probably want to extend with an asynchronous watcher to obtain the logs on-the-fly while the calculation is running.

To do that, we can extend the MultiThreadedTextLogger with a second buffer or queue/hive of buffers

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.

to that extend, should we make this a private method instead? so that later we can choose to flush differently

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I guess so. Made it private. We can specially make it available later if needed

@nitbharambe
nitbharambe force-pushed the pgm/feature/logger-python-api-implementation branch from 3e7516a to d113cdd Compare September 28, 2026 15:57
@nitbharambe nitbharambe added the feature New feature or request label Sep 29, 2026
@nitbharambe
nitbharambe force-pushed the pgm/feature/logger-python-api-implementation branch from 9174b57 to f0a8907 Compare September 29, 2026 09:09
Base automatically changed from pgm/feature/logger-api-implementation to main September 29, 2026 13:06
@mgovers
mgovers force-pushed the pgm/feature/logger-python-api-implementation branch from f0a8907 to 2e3f9d7 Compare September 29, 2026 13:06
@nitbharambe
nitbharambe force-pushed the pgm/feature/logger-python-api-implementation branch from 2f3ac47 to 1cddc94 Compare September 29, 2026 15:27
Comment thread src/power_grid_model/_core/logger.py
Comment on lines +70 to +75
def __init__(
self,
logger_type: LoggerType = LoggerType.info,
*,
python_logger: _logging.Logger | None = None,
level: int = _logging.DEBUG,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I feel this would be a bit confusing for users.

Do i rename level -> python_logging_level?

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.

I feel this would be a bit confusing for users.

Do i rename level -> python_logging_level?

why not keep the same loglevel for both python and C++ where it makes sense?

  • LoggerType.info -> _logging.INFO
  • LoggerType.benchmark -> _logging.DEBUG

or you can do something like override_python_log_level?

Also maybe we need to consider if in the future we decide to support multiple python log levels, then we can get something like

LoggerType.warning_only -> _logging.WARNING
LoggerType.info_only -> _logging.INFO
LoggerType.debug_only -> _logging.DEBUG

as opposed to one LoggerType.info that sends warning level C++ logs to _logging.INFO, which is not great, of course

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.

Please also do note that there may be multi-line C++ core logs all sent to the Python logger in one single event, so maybe we need to split the output

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Regarding 2nd comment, we already split at new lines when we flush to python logger. Is there a requirement to have multiline logs under a single log of python?

_flush_to_python_logger can also be customized in such a case

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Regarding 1st, Since there is a lot of logic involved with levels, lets just let user determine which PGM-internal logging levels map to which of python logging levels.
So we recommend them creating LoggerType.info with _logging.info but not restrict them from creating LoggerType.some_type -> _logging.info

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.

Regarding 2nd comment, we already split at new lines when we flush to python logger. Is there a requirement to have multiline logs under a single log of python?

_flush_to_python_logger can also be customized in such a case

ahhh sorry didn't realize that. i think it's fine. logs aren't meant to be fully stable anyways

@mgovers mgovers left a comment

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.

the rest LGTM

Comment on lines +70 to +75
def __init__(
self,
logger_type: LoggerType = LoggerType.info,
*,
python_logger: _logging.Logger | None = None,
level: int = _logging.DEBUG,

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.

Please also do note that there may be multi-line C++ core logs all sent to the Python logger in one single event, so maybe we need to split the output

Output is non-conclusive and intended as debugging hints for advanced users.
"""

info = 3

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.

no benchmark yet?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Adding. Was waiting on it being available in main. Now added.

Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>
@nitbharambe
nitbharambe force-pushed the pgm/feature/logger-python-api-implementation branch from fdb11d5 to 06384c7 Compare September 30, 2026 13:27
@sonarqubecloud

Copy link
Copy Markdown

Signed-off-by: Nitish Bharambe <nitish.bharambe@alliander.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants