Skip to content

Commit af91edb

Browse files
authored
Feature/logging (#463)
* Update logger imports * Simplify logging options * Use loguru defaults * Update logger format * Add multiline formating * Add multiline formating * Make date fmt dim * Fix Multiline formater * Add verbose tracebacks to logging options * Update docs * Avoid logging entire arrays Use lazy logging for expensive operation * Use warning level instead of critical * Use lazy logging for main results * Fix rotation size calculation * Remove unused logger import * Remove rich import from example * Remove obsolete test Strengthen rotation test Refactor tests to avoid private Loguru APIs * Fix lazy logging * Update CHANGELOG.md * Use logging.sucess * Add sucess level * Add sucess level
1 parent 598b17a commit af91edb

25 files changed

Lines changed: 311 additions & 550 deletions

CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp
5151
5252
## [Unreleased] - ????-??-??
5353
54-
**Summary**: Type system overhaul with comprehensive type hints for better IDE support and code clarity.
54+
**Summary**: Type system overhaul and migration to loguru for logging
5555
5656
If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOpt/flixOpt/releases/tag/v3.0.0) and [Migration Guide](https://flixopt.github.io/flixopt/latest/user-guide/migration-guide-v3/).
5757
@@ -64,8 +64,13 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp
6464
- Added `Scalar` type for scalar-only numeric values
6565
- Added `NumericOrBool` utility type for internal use
6666
- Type system supports scalars, numpy arrays, pandas Series/DataFrames, and xarray DataArrays
67+
- Lazy logging evaluation - expensive log operations only execute when log level is active
68+
- `CONFIG.Logging.verbose_tracebacks` option for detailed debugging with variable values
6769
6870
### 💥 Breaking Changes
71+
- **Logging framework**: Migrated to [loguru](https://loguru.readthedocs.io/)
72+
- Removed `CONFIG.Logging` parameters: `rich`, `Colors`, `date_format`, `format`, `console_width`, `show_path`, `show_logger_name`
73+
- For advanced formatting, use loguru's API directly after `CONFIG.apply()`
6974
7075
### ♻️ Changed
7176
- **Code structure**: Removed `commons.py` module and moved all imports directly to `__init__.py` for cleaner code organization (no public API changes)
@@ -83,13 +88,15 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp
8388
8489
### 📦 Dependencies
8590
- Updated `mkdocs-material` to v9.6.23
91+
- Replaced `rich >= 13.0.0` with `loguru >= 0.7.0` for logging
8692
8793
### 📝 Docs
8894
- Enhanced documentation in `flixopt/types.py` with comprehensive examples and dimension explanation table
8995
- Clarified Effect type docstrings - Effect types are dicts, but single numeric values work through union types
9096
- Added clarifying comments in `effects.py` explaining parameter handling and transformation
9197
- Improved OnOffParameters attribute documentation
92-
98+
- Updated getting-started guide with loguru examples
99+
- Updated `config.py` docstrings for loguru integration
93100
94101
### 👷 Development
95102
- Added test for FlowSystem resampling

docs/getting-started.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ For all features including interactive network visualizations and time series ag
2222
pip install "flixopt[full]"
2323
```
2424

25+
## Logging
26+
27+
FlixOpt uses [loguru](https://loguru.readthedocs.io/) for logging. Logging is silent by default but can be easily configured. For beginners, use our internal convenience methods. Experts can use loguru directly.
28+
29+
```python
30+
from flixopt import CONFIG
31+
32+
# Enable console logging
33+
CONFIG.Logging.console = True
34+
CONFIG.Logging.level = 'INFO'
35+
CONFIG.apply()
36+
37+
# Or use a preset configuration for exploring
38+
CONFIG.exploring()
39+
```
40+
41+
For more details on logging configuration, see the [`CONFIG.Logging`][flixopt.config.CONFIG.Logging] documentation.
42+
2543
## Basic Workflow
2644

2745
Working with FlixOpt follows a general pattern:

examples/02_Complex/complex_example.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import numpy as np
66
import pandas as pd
7-
from rich.pretty import pprint # Used for pretty printing
87

98
import flixopt as fx
109

@@ -188,7 +187,7 @@
188187
flow_system.add_elements(Costs, CO2, PE, Gaskessel, Waermelast, Gasbezug, Stromverkauf, speicher)
189188
flow_system.add_elements(bhkw_2) if use_chp_with_piecewise_conversion else flow_system.add_elements(bhkw)
190189

191-
pprint(flow_system) # Get a string representation of the FlowSystem
190+
print(flow_system) # Get a string representation of the FlowSystem
192191
try:
193192
flow_system.start_network_app() # Start the network app
194193
except ImportError as e:

examples/05_Two-stage-optimization/two_stage_optimization.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@
77
While the final optimum might differ from the global optimum, the solving will be much faster.
88
"""
99

10-
import logging
1110
import pathlib
1211
import timeit
1312

1413
import pandas as pd
1514
import xarray as xr
15+
from loguru import logger
1616

1717
import flixopt as fx
1818

19-
logger = logging.getLogger('flixopt')
20-
2119
if __name__ == '__main__':
2220
fx.CONFIG.exploring()
2321

flixopt/aggregation.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
from __future__ import annotations
77

88
import copy
9-
import logging
109
import pathlib
1110
import timeit
1211
from typing import TYPE_CHECKING
1312

1413
import numpy as np
14+
from loguru import logger
1515

1616
try:
1717
import tsam.timeseriesaggregation as tsam
@@ -37,8 +37,6 @@
3737
from .elements import Component
3838
from .flow_system import FlowSystem
3939

40-
logger = logging.getLogger('flixopt')
41-
4240

4341
class Aggregation:
4442
"""
@@ -106,7 +104,7 @@ def cluster(self) -> None:
106104
self.aggregated_data = self.tsam.predictOriginalData()
107105

108106
self.clustering_duration_seconds = timeit.default_timer() - start_time # Zeit messen:
109-
logger.info(self.describe_clusters())
107+
logger.opt(lazy=True).info('{result}', result=lambda: self.describe_clusters())
110108

111109
def describe_clusters(self) -> str:
112110
description = {}

flixopt/calculation.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
from __future__ import annotations
1212

13-
import logging
1413
import math
1514
import pathlib
1615
import sys
@@ -20,6 +19,7 @@
2019
from typing import TYPE_CHECKING, Annotated, Any
2120

2221
import numpy as np
22+
from loguru import logger
2323
from tqdm import tqdm
2424

2525
from . import io as fx_io
@@ -39,8 +39,6 @@
3939
from .solvers import _Solver
4040
from .structure import FlowSystemModel
4141

42-
logger = logging.getLogger('flixopt')
43-
4442

4543
class Calculation:
4644
"""
@@ -238,7 +236,7 @@ def solve(
238236
**solver.options,
239237
)
240238
self.durations['solving'] = round(timeit.default_timer() - t_start, 2)
241-
logger.info(f'Model solved with {solver.name} in {self.durations["solving"]:.2f} seconds.')
239+
logger.success(f'Model solved with {solver.name} in {self.durations["solving"]:.2f} seconds.')
242240
logger.info(f'Model status after solve: {self.model.status}')
243241

244242
if self.model.status == 'warning':
@@ -255,12 +253,10 @@ def solve(
255253
# Log the formatted output
256254
should_log = log_main_results if log_main_results is not None else CONFIG.Solving.log_main_results
257255
if should_log:
258-
logger.info(
259-
f'{" Main Results ":#^80}\n'
260-
+ fx_io.format_yaml_string(
261-
self.main_results,
262-
compact_numeric_lists=True,
263-
)
256+
logger.opt(lazy=True).info(
257+
'{result}',
258+
result=lambda: f'{" Main Results ":#^80}\n'
259+
+ fx_io.format_yaml_string(self.main_results, compact_numeric_lists=True),
264260
)
265261

266262
self.results = CalculationResults.from_calculation(self)
@@ -673,7 +669,7 @@ def do_modeling_and_solve(
673669
for key, value in calc.durations.items():
674670
self.durations[key] += value
675671

676-
logger.info(f'Model solved with {solver.name} in {self.durations["solving"]:.2f} seconds.')
672+
logger.success(f'Model solved with {solver.name} in {self.durations["solving"]:.2f} seconds.')
677673

678674
self.results = SegmentedCalculationResults.from_calculation(self)
679675

flixopt/color_processing.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66

77
from __future__ import annotations
88

9-
import logging
10-
119
import matplotlib.colors as mcolors
1210
import matplotlib.pyplot as plt
1311
import plotly.express as px
12+
from loguru import logger
1413
from plotly.exceptions import PlotlyError
1514

16-
logger = logging.getLogger('flixopt')
17-
1815

1916
def _rgb_string_to_hex(color: str) -> str:
2017
"""Convert Plotly RGB/RGBA string format to hex.

flixopt/components.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
from __future__ import annotations
66

7-
import logging
87
import warnings
98
from typing import TYPE_CHECKING, Literal
109

1110
import numpy as np
1211
import xarray as xr
12+
from loguru import logger
1313

1414
from . import io as fx_io
1515
from .core import PlausibilityError
@@ -25,8 +25,6 @@
2525
from .flow_system import FlowSystem
2626
from .types import Numeric_PS, Numeric_TPS
2727

28-
logger = logging.getLogger('flixopt')
29-
3028

3129
@register_class_for_io
3230
class LinearConverter(Component):

0 commit comments

Comments
 (0)