Skip to content

ENH: Add python loggers#973

Draft
YuriCastroDev wants to merge 17 commits into
RocketPy-Team:developfrom
YuriCastroDev:enh/issue-450-adopt-python-loggers
Draft

ENH: Add python loggers#973
YuriCastroDev wants to merge 17 commits into
RocketPy-Team:developfrom
YuriCastroDev:enh/issue-450-adopt-python-loggers

Conversation

@YuriCastroDev

@YuriCastroDev YuriCastroDev commented Jun 19, 2026

Copy link
Copy Markdown

Pull request type

  • Code changes (bugfix, features)
  • Code maintenance (refactoring, formatting, tests)

Checklist

  • Tests for the changes have been added (if needed)
  • Docs have been reviewed and added / updated
  • Lint (black rocketpy/ tests/) has passed locally
  • All tests (pytest tests -m slow --runslow) have passed locally
  • CHANGELOG.md has been updated (if relevant)

Current behavior

RocketPy uses bare print() calls scattered across the codebase to report simulation progress, warnings, and errors. This approach has no severity levels, cannot be redirected to a file, and cannot be silenced or filtered by the end user. Closes #450.

New behavior

Internal runtime events now use Python's built-in logging module following best practices for libraries, while user-requested output (.info(), .all_info()) continues to use print() unchanged.

What changed:

  • rocketpy/__init__.py registers a NullHandler, so the library is silent by default with no output unless the user configures a handler.
  • 27 execution modules now expose logger = logging.getLogger(__name__), creating a hierarchy (rocketpy.simulation.flight, rocketpy.environment.environment, etc.) that users can filter individually.
  • Log levels assigned according to severity:
    • DEBUG: high-frequency solver ticks, internal detail
    • INFO: operation confirmations (simulation completed, files saved)
    • WARNING: unexpected but recoverable situations (missing motor, geometry auto-corrected, feature silently skipped)
    • ERROR: optional dependency unavailable, feature broken
  • rocketpy/prints/ folder kept as print() methods like flight.info()
    and rocket.all_info() continue to print directly to the terminal as before.
  • _SimMonitor.reprint() in MonteCarlo kept for backwards compatibility and now delegates to logger.info().
  • New rocketpy/utils.py with enable_logging() helper function so users can activate logging with a single line:
import rocketpy
rocketpy.utils.enable_logging(level="INFO")

Note on verbose parameter: Flight(verbose=True) retains its original real-time terminal progress ticker. The same information is also emitted via logger.debug(), so users who configure a logging handler will capture it as well.

Tests updated: 3 existing tests migrated from capsys to caplog where the output source changed from print() to logger.*. 6 new unit tests added for rocketpy.utils.enable_logging().

Breaking change

  • No

Additional information

  • 31 files modified (27 source + 3 tests + 1 new utils.py).

@YuriCastroDev YuriCastroDev requested a review from a team as a code owner June 19, 2026 21:01

@Gui-FernandesBR Gui-FernandesBR 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.

does it change current behavior?

If I open the getting start notebook, does it work just like as it should?

@YuriCastroDev

Copy link
Copy Markdown
Author

@Gui-FernandesBR yes, it does change current behavior. The getting started notebook would not work the same because .info() / .all_info() calls are now silent due to the nullhandler. To get the same output, the user would need to configure a handler before running simulation.

@Gui-FernandesBR

Copy link
Copy Markdown
Member

@Gui-FernandesBR yes, it does change current behavior. The getting started notebook would not work the same because .info() / .all_info() calls are now silent due to the nullhandler. To get the same output, the user would need to configure a handler before running simulation.

yes that's my concern... Is there a way where we keep the same behavior for current code, but also benefit from built-in loggers without duplicating code? thta's the real challenge

@YuriCastroDev

Copy link
Copy Markdown
Author

Hm... makes sense. Keeping print() for explicitly user-requested output
like flight.info() and reserving logger for internal runtime events
(simulation completed, file saved, motor overwritten, etc.) follows
the Python logging guide's own distinction.

What do u think?

@Gui-FernandesBR

Copy link
Copy Markdown
Member

Hm... makes sense. Keeping print() for explicitly user-requested output like flight.info() and reserving logger for internal runtime events (simulation completed, file saved, motor overwritten, etc.) follows the Python logging guide's own distinction.

What do u think?

yes but that would imply in us duplicating code verytime we want to print a message, right?

I wonder how other simulator libraries deal with the same situation.

If you could bring us some references so we can base our opinion on different examples... I'd appreciate it a lot.

@YuriCastroDev

Copy link
Copy Markdown
Author

I'll look into other libraries for references, once I have the answer I'll come back, tks for review

@YuriCastroDev YuriCastroDev marked this pull request as draft June 22, 2026 10:44
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.92683% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.20%. Comparing base (9cf3dd4) to head (2fb3fe3).
⚠️ Report is 80 commits behind head on develop.

Files with missing lines Patch % Lines
rocketpy/simulation/monte_carlo.py 41.66% 7 Missing ⚠️
rocketpy/environment/environment_analysis.py 28.57% 5 Missing ⚠️
rocketpy/plots/aero_surface_plots.py 50.00% 4 Missing ⚠️
rocketpy/plots/monte_carlo_plots.py 33.33% 4 Missing ⚠️
rocketpy/rocket/rocket.py 50.00% 3 Missing ⚠️
rocketpy/mathutils/function.py 66.66% 1 Missing ⚠️
rocketpy/plots/environment_plots.py 83.33% 1 Missing ⚠️
rocketpy/simulation/flight.py 80.00% 1 Missing ⚠️
rocketpy/simulation/flight_comparator.py 93.33% 1 Missing ⚠️
rocketpy/simulation/flight_data_exporter.py 80.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #973      +/-   ##
===========================================
+ Coverage    80.27%   81.20%   +0.93%     
===========================================
  Files          104      114      +10     
  Lines        12769    14726    +1957     
===========================================
+ Hits         10250    11958    +1708     
- Misses        2519     2768     +249     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Gui-FernandesBR

Copy link
Copy Markdown
Member

@YuriCastroDev you let me know when this PR is ready for review, ok? Thx a lot for your contribution!

@YuriCastroDev YuriCastroDev marked this pull request as ready for review June 22, 2026 15:08
@YuriCastroDev

Copy link
Copy Markdown
Author

@Gui-FernandesBR The PR is ready for your review! Thanks for your support! :)

Comment thread rocketpy/environment/environment.py Outdated
Comment thread rocketpy/environment/environment.py Outdated
Comment thread rocketpy/environment/tools.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates runtime/progress output across RocketPy from scattered print() calls to Python’s logging module, adding a library-friendly default configuration (silent unless configured) and a small helper API to enable console logging.

Changes:

  • Add rocketpy.utils.enable_logging() to configure a StreamHandler and set the rocketpy logger level.
  • Replace print() usage with module-level loggers (logging.getLogger(__name__)) across simulation, environment, plots, and utilities.
  • Update tests to validate and capture logging output via caplog, and add new unit tests for enable_logging().

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/unit/test_utils.py Adds unit tests and a logger-reset fixture for rocketpy.utils.enable_logging().
tests/unit/test_rail_buttons_bending_moments.py Migrates a plot-skip assertion from stdout capture (capsys) to logging capture (caplog).
tests/unit/simulation/test_flight_comparator.py Updates comparator output assertions from print() to logging via caplog.
rocketpy/utils.py Introduces enable_logging() helper for end-user logging activation.
rocketpy/utilities.py Replaces flutter analysis print() output with structured logger.info() messages.
rocketpy/tools.py Adds module logger and replaces __main__ doctest result prints with log records.
rocketpy/stochastic/stochastic_model.py Replaces report print() with logger.info().
rocketpy/simulation/monte_carlo.py Replaces _SimMonitor/MonteCarlo progress prints with logger.*() calls; keeps reprint() as compatibility shim.
rocketpy/simulation/flight.py Adds module logger; emits progress/completion via logging alongside existing verbose printing.
rocketpy/simulation/flight_data_importer.py Converts attribute/unit conversion prints to debug/info logging.
rocketpy/simulation/flight_data_exporter.py Converts export status prints to info logging.
rocketpy/simulation/flight_comparator.py Converts comparator status/summary prints to logging and updates messages accordingly.
rocketpy/sensors/sensor.py Converts sensor data export prints to info logging (including multi-file saves).
rocketpy/sensitivity/sensitivity_model.py Converts optional-dependency import error prints to error logging.
rocketpy/rocket/rocket.py Converts motor-association warnings and overwrite warning from print to logger warnings.
rocketpy/rocket/aero_surface/nose_cone.py Converts nose cone length adjustment print to warning log.
rocketpy/plots/rocket_plots.py Converts plot “section header” prints to info logs.
rocketpy/plots/monte_carlo_plots.py Converts missing-data skip prints to warning logs.
rocketpy/plots/flight_plots.py Converts various plot availability/status prints to info/warning logs.
rocketpy/plots/environment_plots.py Converts plot status prints to info logs.
rocketpy/plots/compare/compare_flights.py Converts save/“not implemented” prints to info/warning logs.
rocketpy/plots/aero_surface_plots.py Converts plot preface prints to info logs.
rocketpy/motors/tank_geometry.py Converts spherical-cap warning print to warning log.
rocketpy/mathutils/vector_matrix.py Adds module logger and converts __main__ doctest result prints to logs.
rocketpy/mathutils/function.py Adds module logger and converts plotting error/doctest __main__ prints to logs.
rocketpy/environment/tools.py Adds module logger and converts __main__ doctest result prints to logs.
rocketpy/environment/fetchers.py Converts elevation-fetch print to debug logging.
rocketpy/environment/environment.py Converts elevation/topographic/export status prints to info/debug logs.
rocketpy/environment/environment_analysis.py Converts requirement/unit-system/export/save prints to warning/info/error logs.
rocketpy/init.py Adds a NullHandler for library-safe default silence and exposes rocketpy.utils.
CHANGELOG.md Adds a changelog entry for the logging adoption enhancement.

Comment thread rocketpy/utils.py Outdated
Comment thread rocketpy/simulation/flight.py Outdated
Comment thread rocketpy/simulation/monte_carlo.py Outdated
Comment on lines +1656 to +1657

_SimMonitor.reprint(msg, end="\r", flush=True)
logger.debug(msg)
Comment thread rocketpy/simulation/flight_comparator.py
Comment thread rocketpy/mathutils/function.py Outdated
Comment thread rocketpy/mathutils/vector_matrix.py Outdated
YuriCastroDev and others added 5 commits June 22, 2026 14:35
Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com>
Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com>
Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com>
Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com>
Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com>
Comment on lines -421 to +426
sim_monitor.reprint(
"Simulation Interrupt, files from simulation "
f"{sim_idx} saved."
logger.warning(
"Simulation interrupt. Files from simulation %d saved.",
sim_idx,

@phmbressan phmbressan Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@YuriCastroDev

Have you checked if these changes behave well regarding parallel monte carlo?

The sim_monitor was in use to have a shared instance that makes sure concurrent messaging will not end up mangled in the shell output. Perhaps the logging API can do this out of the box, I am not sure.

One way to check would be either:

  1. Running the slow test that specifically has a parallel monte carlo run with a -s flag to capture the output and keep an eye on the logged messages. E.g.:
pytest -m slow -s --runslow tests/integration/simulation/test_monte_carlo.py
  1. Or, run the notebook in docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb, which has a parallel monte carlo run.

From a very quick search, here is what the Python docs has to say about it. It seems that multiprocessing logging might not be straightforward.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@phmbressan

I'll check this and get back to you. Any other edge case you'd like me to verify besides the parallel monte carlo run, or is this the main concern?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I believe the other comments already address anything else I had in mind. Good work on using "%" strings rather than f-strings, it should be better for performance.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@phmbressan

I ran the verification as you suggested with:

pytest -m slow -s --runslow tests/integration/simulation/test_monte_carlo.py

The progress ticker was indeed silent because _SimMonitor runs in a separate process and logging doesn't work in that context. I fixed it by keeping print() in those methods, the output looks correct and all 4 tests passed.

Commit: 2fb3fe3

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.

Do you agree that these message will stop making sense here?

The prints existed to separated each plot from the next one.
If we turn these into info logs, the user may not seeing them (unless they implement a handler).

On the other hand, if a user consumes the log without seeing the plot, it doesn't really make sense at all (i.e. reading "airfoil lift curve" doesn't make as much sense as reading "plotting airfoil lift curve")

In other words, we need to rethink what we really want to display in each message within the plots module.

Comment on lines -448 to 457
print(
"Due to the chosen bluffness ratio, the nose "
f"cone length was reduced to {self.length} m."
logger.warning(
"Due to the chosen bluffness ratio, the nose cone length was "
"reduced to %.4f m.",
self.length,
)
self.fineness_ratio = self.length / (2 * self.base_radius)

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.

we are suprassing somehting really important here, no?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Indeed, since this is a warning about an automatic change, I used UserWarning "the code worked, but something happened that you should know about".
Commit: a29f05f

Comment thread rocketpy/tools.py Outdated
logger.info("All the %d tests passed!", res.attempted)
else:
print(f"{res.failed} out of {res.attempted} tests failed.")
logger.warning("%d out of %d tests failed.", res.failed, res.attempted)

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 search and replace in the entire codebase...

        logger.error("%d out of %d tests failed.", res.failed, res.attempted)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ok, I found only one occurrence.
Commit: a29f05f

Comment thread rocketpy/utils.py

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.

could you kindly add a documentation within docs/ folder teaching how to use it?

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 docstring already helps a lot, but beginners may benefit from a more detailed instruction, perhaps adding it to the getting started notebook could help!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Sure, it'll be a pleasure! After addressing all the remaining comments, I'll take care of it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@Gui-FernandesBR

I was thinking about adding something to the PR template, but haven't fully thought it out yet, my idea would be to remind reviewers to always check print() vs logger.* usage. What do u think? any ideas?

@Gui-FernandesBR Gui-FernandesBR 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.

I already reviewd 23/31 files. there are some changes I already see as important.
But overall the Pr looks great!

@Gui-FernandesBR

Copy link
Copy Markdown
Member

@YuriCastroDev please let me know when you fix all the comments.

I will mark the PR as "draft' once again

@YuriCastroDev YuriCastroDev marked this pull request as draft June 26, 2026 00:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ENH: adoption of the built-in python loggers instead of simple prints

4 participants