Tango makes heavy use of the
logging module from the standard library to convey information to users.
When you’re writing your own
Step implementations we encourage you to also use standard
Python logging as opposed to
print() or other functions that write directly to
This is easy enough since each
Step class already comes with its own logger:
When using the Tango CLI you can set the log level in several different ways:
Through a Tango global settings file.
With the environment variable
Or with the
Configuring logging in your own CLI#
If you’re writing your own CLI that uses tango, you can utilize the
function to easily configure logging properly.
from tango.common.logging import initialize_logging, teardown_logging initialize_logging(log_level="info") logger = logging.getLogger() logger.info("Running script!") teardown_logging()
[...] INFO Running script! ...
If you want to have logs written to a file, you can use the
file_handler() context manager.
Logging from worker processes or threads#
If you have steps or other functions that spawn workers, and you want to enable logging within
those workers, you can call the
initialize_worker_logging() function to configure
logging within each worker. This assumes that you’ve called
initialize_logging() from the
main process (the tango CLI does this for you).
import logging import multiprocessing as mp from tango import Step from tango.common.logging import initialize_worker_logging @Step.register("multiprocessing_step_example") class MultiprocessingStep(Step): def run(self, num_proc: int = 2) -> bool: # type: ignore workers =  for i in range(num_proc): worker = mp.Process(target=_worker_function, args=(i,)) workers.append(worker) worker.start() for worker in workers: worker.join() return True def _worker_function(worker_id: int): initialize_worker_logging(worker_rank=worker_id) logger = logging.getLogger(MultiprocessingStep.__name__) logger.info("Hello from worker %d!", worker_id)
- tango.common.logging.TANGO_LOG_LEVEL: Optional[str] = None#
The log level to use globally. The value can be set from the corresponding environment variable (
TANGO_LOG_LEVEL) or field in a
log_level), or from the command line with the
--log-leveloption. Possible values are “debug”, “info”, “warning”, or “error” (not case sensitive). For example,
$ tango --log-level info run ...
- tango.common.logging.FILE_FRIENDLY_LOGGING: bool = False#
If this flag is set to
True, we remove special styling characters from log messages, add newlines to
Tqdmoutput even on an interactive terminal, and we slow down
Tqdm’s output to only once every 10 seconds.
Unfortunately this won’t affect
tqdmoutput from other libraries that don’t use Tango’s
By default, it is set to
False. It can be changed by setting the corresponding environment variable (
FILE_FRIENDLY_LOGGING) or field in a
file_friendly_logging) to “true” or “false”, or from the command line with the
--file-friendly-loggingflag. For example,
$ tango --file-friendly-logging run ...
- tango.common.logging.cli_logger = <Logger tango.__main__ (WARNING)>#
This provides a convenient way for command-line apps to log pretty, styled messages uses the markup style provided by rich.
- tango.common.logging.initialize_logging(*, log_level=None, enable_cli_logs=None, file_friendly_logging=None)#
Initialize logging, which includes setting the global log level, format, and configuring handlers.
This should be called as early on in your script as possible.
You should also call
teardown_logging()as the end of your script.
For worker threads/processes, use
Initialize logging in a worker thread/process.
- tango.common.logging.initialize_prefix_logging(*, log_level=None, prefix=None, main_process=False)#
Initialize logging with a prefix.
False) – Whether it is for the main/worker process.
Cleanup any logging fixtures created from
initialize_logging(). Should be called at the end of your script.
A context manager that can be used to route logs to a file by adding a
logging.FileHandlerto the root logger’s handlers.
from tango.common.logging import initialize_logging, file_handler, teardown_logging initialize_logging(log_level="info") logger = logging.getLogger() logger.info("Hi!") with file_handler("log.out"): logger.info("This message should also go into 'log.out'") teardown_logging()
- Return type: