Logging#
IDAES provides some logging extensions to provide finer control over information logging and to allow solver output to be logged. Logging can be a useful tool for debugging.
Getting Loggers#
There are four main roots of IDAES loggers (idaes
, idaes.model
,
idaes.init
, idaes.solve
). All of these loggers are standard Python
loggers, and can be used as such. The main differences between using the IDAES
logging functions to get the loggers and plain Python methods are that
the IDAES functions make it a little easier to get loggers that fit into IDAES’s
standard logging hierarchy, and the IDAES loggers have a few additional named
logging levels, which allow for finer control over the information displayed.
Logging levels are described in detail later.
A tag can also be specified and used to filter logging records. By default the
tag is None and log records won’t be filtered. Valid tags are in the set {None,
"framework", "model", "flowsheet", "unit", "control_volume", "properties",
"reactions"}
. Users may add to the set of valid names. To see how
to control which logging tags are logged, see section “Tags” below. To avoid
filtering out import warning and error messages, records logged at the WARNING
level and above are not filtered out regardless of tag.
idaes Logger#
Loggers descending from idaes
(other than idaes.init
, idaes.model
, or
idaes.solve
) are used for general IDAES framework logging. Typically the
module name __name__
is used for the logger name. Modules in the idaes
package already start with idaes
, but if an IDAES logger is requested for a
module outside of the idaes
package idaes.
is prepended to the name.
- idaes.logger.getLogger(name, level=None, tag=None)
Return an idaes logger.
- Parameters:
name – usually __name__
level – standard IDAES logging level (default use IDAES config)
tag – logger tag for filtering, see valid_log_tags()
- Returns:
logger
Example
import idaes.logger as idaeslog
_log = idaeslog.getLogger(__name__, tag="framework")
idaes.init Loggers#
The init logger will always descend from “idaes.init”. This logger is used in
IDAES model initialization methods, and can be used in user models as well.
Initialization methods are usually attached to a Pyomo Block. Blocks have a
name
attribute. So the logger name is usually given as the block name, and
the getInitLogger()
function prepends idaes.init.
. The advantage of using
the block name over the module name is that users can see exactly which model
instance the initialization log messages are coming from.
- idaes.logger.getInitLogger(name, level=None, tag=None)[source]
Get a model initialization logger
- Parameters:
name – Object name (usually Pyomo Component name)
level – Log level
tag – logger tag for filtering, see valid_log_tags()
- Returns:
logger
Example
import idaes.logger as idaeslog
class DummyBlock(object):
"""A dummy block for demonstration purposes"""
def __init__(name):
self.name = name
def initialize(outlvl=idaeslog.INFO):
init_log = idaeslog.getInitLogger(self.name, level=outlvl, tag="unit")
idaes.model Loggers#
The model logger is used to provide a standard way to produce log messages from
user models that are not part of the idaes
package. The logger name has
idaes.model
prepended to the name provided by the user. This is convenient
because it provides a way to use a standard configuration system for user model
loggers. The user can choose any name they like for these loggers.
- idaes.logger.getModelLogger(name, level=None, tag=None)[source]
Get a logger for an IDAES model. This function helps users keep their loggers in a standard location and use the IDAES logging config.
- Parameters:
name – Name (usually __name__). Any starting ‘idaes.’ is stripped off, so if a model is part of the idaes package, ‘idaes’ won’t be repeated.
level – Standard Python logging level (default use IDAES config)
tag – logger tag for filtering, see valid_log_tags()
- Returns:
logger
Example
import idaes.logger as idaeslog
_log = idaeslog.getModelLogger("my_model", level=idaeslog.DEBUG, tag="model")
idaes.solve Loggers#
The solve logger will always descend from “idaes.solve”. This logger is used to log solver output. Since solvers may produce a lot of output, it can be useful to specify different handlers for the solve logger to direct it to a separate file.
- idaes.logger.getSolveLogger(name, level=None, tag=None)[source]
Get a solver logger
- Parameters:
name – logger name is “idaes.solve.” + name (if name starts with “idaes.” it is removed before creating the logger name)
level – Log level
tag – logger tag for filtering, see valid_log_tags()
- Returns:
logger
Levels#
Several logging level constants are defined in the idaes.logger
module. These
include the standard Python Levels. The following levels are provided for IDAES
loggers. The additional levels of info provide finer control over the amount of
logging information produced by IDAES loggers.
Constant Name |
Value |
Name |
Log Method |
---|---|---|---|
CRITICAL |
50 |
CRITICAL |
|
ERROR |
40 |
ERROR |
|
WARNING |
30 |
WARNING |
|
INFO_LOW |
21 |
INFO |
|
INFO |
20 |
INFO |
|
INFO_HIGH |
19 |
INFO |
|
DEBUG |
10 |
DEBUG |
|
NOTSET |
0 |
NOTSET |
– |
Utility Functions#
There are some additional utility functions to perform logging tasks that are common in the IDAES framework.
- idaes.logger.condition(res)[source]
Get the solver termination condition to log. This isn’t a specific value that you can really depend on, just a message to pass on from the solver for the user’s benefit. Sometimes the solve is in a try-except, so we’ll handle None and str for those cases, where you don’t have a real result.
Logging Solver Output#
The solver output can be captured and directed to a logger using the
idaes.logger.solver_log(logger, level)
context manager, which uses
pyomo.common.tee.capture_output()
to temporarily redirect
sys.stdout
and sys.stderr
to a string buffer. The logger
argument is the logger to log to, and the level
argument is the
level at which records are sent to the logger. The output is logged by a
separate logging thread, so output can be logged as it is produced
instead of after the solve completes. If the solver_log()
context
manager is used, it can be turned on and off by using the
idaes.logger.solver_capture_on()
and
idaes.logger.solver_capture_off()
functions. If the capture is off
solver output won’t be logged and it will go to standard output as
usual.
The solver_log
context yields an object with the tee
attribute, which should be passed to the tee
argument of the solve
method. Tee tells the Pyomo solver to
display solver output. The solver log context can provide this argument
by determining if the solver output would be logged at the given level.
Example
import idaes.logger as idaeslog
import pyomo.environ as pyo
solver = pyo.SolverFactory("ipopt")
model = pyo.ConcreteModel()
model.x = pyo.Var()
model.y = pyo.Var()
model.x.fix(3)
model.c = pyo.Constraint(expr=model.y==model.x**2)
log = idaeslog.getSolveLogger("solver.demo")
log.setLevel(idaeslog.DEBUG)
with idaeslog.solver_log(log, idaeslog.DEBUG) as slc:
res = solver.solve(model, tee=slc.tee)