Using the Logging Infrastructure#

OpenROAD uses spdlog as part of logging infrastructure in order to ensure a clear, consistent messaging and complete messaging interface. A wrapper formats the prefix in the recommended messaging style and limit. A message format is as follows:

<tool id>-<message id>  <Message body>.

For example,

[INFO ODB-0127] Reading DEF file: ./results/asap7/aes/base/4_cts.def

All output from OpenROAD tools should be directed through the logging API to ensure that redirection, file logging and execution control flow are handled consistently. This also includes messages from any third-party tool. Use the ‘ord’ message ID for third-party tools.

The logging infrastructure also supports generating a JSON file containing design metrics (e.g., area or slack). This output is directed to a user-specified file. The OpenROAD application has a -metrics command line argument to specify the file.

Handling Messages#

OpenROAD supports multiple levels of severity for message outputs: critical, error, warning, information and debug. These are supported by automatic calls to the logger which will then prefix the appropriate severity type to the message.

C++20 Requirements#

In C++20 the logger messages are checked during compile time which introduces restrictions around rutime format strings. See docs.

OpenROAD uses spdlog which uses fmt_lib under the hood. Below is an example of what is no longer allowed.

In order to make use of runtime format strings, we have introduced a FMT_RUNTIME macro in Logger.h. You should use this macro any time you pass a dynamic string as the format string

logger_->info("{} {}", a, b); // OK

void blah(std::string template& a) {
  logger_->info(a, c); // Illegal
  logger_->info(FMT_RUNTIME(a), c); // Ok

Messaging Guidelines#

In addition to the proper use of message types, follow the guidelines below to compose messages for clarity, consistency and other guidelines:


Start with a capital letter and end with a period, besides well-known exceptions. Use capital letters for file formats and tool proper names, e.g., LEF, DEF, SPICE, FLUTE.

After the first word’s capitalization, do not use capital letters (aside from obvious exceptions, such as RSMT, hCut, etc.).

Do not use exclamations. Severity must be communicated by message severity and clear implied or explicit action.

Avoid long, verbose messages. Use commas to list and separate clauses in messages.

Spellcheck all messages using American English spellings.

Use ellipsis ... only to indicate a pause, as when some tool is running or being initialized.

Abbreviations and Shortcuts#

Use single-word versions when well-accepted / well-understood by users and developers. Examples: stdcell, cutline, wirelength, flipchip, padring, bondpad, wirebond, libcell, viarule.

Do not abbreviate or truncate English words; expand for the sake of clarity.

Incorrect:   Num, #;  Tot.
Correct:     Number;  Total

Use acceptable, well-understood abbreviations for brevity. Examples: db, tech, lib, inst, term, params, etc.

Avoid contractions of action words:

Incorrect:   Can't, Can not;  Don't
Correct:     Cannot;  Do not


Messages should communicate a clear, implied or explicit action that is necessary for flow continuation or improved quality of results.

A value for core_area must be specified in the footprint specification, or in the environment variable CORE_AREA.


Messages must be clear and complete, so as to communicate necessary and sufficient information and actions. Elaborate specific variables, options, and/or parameters to avoid any ambiguity.

Unrecognized argument $arg, should be one of -pitch, -bump_pin_name, -spacing_to_edge, -cell_name, -bumps_per_tile, -rdl_layer, -rdl_width, -rdl_spacing.

Specify objects clearly in the local context:

cutWithin is smaller than cutSpacing for ADJACENTCUTS on layer {}. Please check your rule definition.

Warning: {} does not have viaDef aligned with layer.

Make any assumptions or use of default values explicit:

No net slacks found.
Timing-driven mode disabled.

Incomplete, missing default:
Utilization exceeds 100%.

Use simple language, and avoid repetitions:

Missing orientation for cell $cell_ref.

No orientation available for orientation of $cell_ref.

Message Types#

OpenROAD supports the following levels of severity through the logger: report, debug, information, warning, error and critical.


Report messages are output by the tool in the form of a report to the user. Examples include timing paths or power analysis results.

Example report message:

Path startpoint: $startpoint


Debug messages are only of use to tool developers and not to end users. These messages are not shown unless explicitly enabled.


Information messages may be used to report metrics, quality of results, or program status to the user. Any message which indicates runtime problems, such as potential faulty input or other internal program issues, should be issued at a higher status level.

Example information messages:

Number of input ports: 47

Running optimization iteration 2

Current cell site utilization: 57.1567%


Warnings should be used to indicate atypical runtime conditions that may affect quality, but not correctness, of the output. Any conditions that affect correctness should be issued at a higher status level.

Example warning messages:

Core area utilization is greater than 90%. The generated cell placement may not be routable.

14 outputs are not constrained for max capacitance.

Pin 'A[0]' on instance 'mem01' does not contain antenna information and will not be checked for antenna violations.


Error messages should be used to indicate correctness problems. Problems with command arguments are a good example of where error messages are appropriate. Errors exit the current command by throwing an exception that is converted to an error in Tcl. Errors that occur while reading a command file stop execution of the script commands.

Example error messages:

Invalid selection: net 'test0' does not exist in the design.

Cell placement cannot be run before floorplanning.

Argument 'max_routing_layer' expects an integer value from 1 to 10.


Critical messages should be used to indicate correctness problems that the program is not able to work around or ignore, and that require immediate exiting of the program (abort).

Example critical messages:

Database 'chip' has been corrupted and is not recoverable.

Unable to allocate heap memory for array 'vertexIndices'. The required memory size may exceed host machine limits.

Assertion failed: 'nodeVisited == false' on line 122 of example.cpp. Please file a Github issue and attach a testcase.


Each status message requires:

  • The three letter tool ID

  • The message ID

  • The message string

  • Optionally, additional arguments to fill in placeholders in the message string

Reporting is simply printing and does not require a tool or message ID. The tool ID comes from a fixed enumeration of all the tools in the system. This enumeration is in Logger.h. New abbreviations should be added after discussion with the OpenROAD system architects. The abbreviation matches the C++ namespace for the tool.

Message IDs are integers. They are expected to be unique for each tool. This has the benefit that a message can be mapped to the source code unambiguously even if the text is not unique. Maintaining this invariant is the tool owner’s responsibility. To ensure that the IDs are unique, each tool should maintain a file named ‘messages.txt’ in the top-level tool directory, listing the message IDs along with the format string. When code that uses a message ID is removed, the ID should be retired by removing it from ‘messages.txt’. See the utility etc/ to scan a tool directory and write a messages.txt file.

Spdlog comes with the fmt library which supports message formatting in a python or C++20 like style.

The message string should not include the tool ID or message ID which will automatically be prepended. A trailing newline will automatically be added, and hence messages should not end with one. Messages should be written as complete sentences and end in a period. Multi-line messages may contain embedded new lines.

Some examples:

logger->report("Path startpoint: {}", startpoint);

logger->error(ODB, 25, "Unable to open LEF file {}.", file_name);

logger->info(DRT, 42, "Routed {} nets in {:3.2f}s.", net_count, elapsed_time);

Tcl functions for reporting messages are defined in the OpenROAD swig file OpenRoad.i. The message is simply a Tcl string (no C++20 formatting).

utl::report "Path startpoint: $startpoint"

utl::error ODB 25 "Unable to open LEF file $file_name."

utl::info DRT 42 "Routed $net_count nets in [format %3.2f $elapsed_time]."

utl::report should be used instead of ‘puts’ so that all output is logged.

Calls to the Tcl functions utl::warn and utl::error with a single message argument report with tool ID UKN and message ID 0000.

Tools use #include utl/Logger.h that defines the logger API. The Logger instance is owned by the OpenROAD instance. Each tool should retrieve the logger instance in the tool init function called after the tool make function by the OpenROAD application.

Every tool swig file must include src/Exception.i so that errors thrown by utl::error are caught at the Tcl command level. Use the following swig command before %inline.

%include "../../Exception.i"

The logger functions are shown below.

Logger::report(const std::string& message,
               const Args&... args)
Logger::info(ToolId tool,
             int id,
             const std::string& message,
             const Args&... args)
Logger::warn(ToolId tool,
             int id,
             const std::string& message,
             const Args&... args)
Logger::error(ToolId tool,
              int id,
              const std::string& message,
              const Args&... args)
Logger::critical(ToolId tool,
                 int id,
                 const std::string& message,
                 const Args&... args)

The corresponding Tcl functions are shown below.

utl::report message
utl::info tool id message
utl::warn tool id message
utl::error tool id message
utl::critical tool id message

Although there is a utl::critical function, it is really difficult to imagine any circumstances that would justify aborting execution of the application in a tcl function.

Debug Messages#

Debug messages have a different programming model. As they are most often not issued the concern is to avoid slowing down normal execution. For this reason such messages are issued by using the debugPrint macro. This macro will avoid evaluating its arguments if they are not going to be printed. The API is:

debugPrint(logger, tool, group, level, message, ...);

The debug() method of the Logger class should not be called directly. No message id is used as these messages are not intended for end users. The level is printed as the message id in the output.

The argument types are as for the info/warn/error/critical messages. The one additional argument is group which is a const char*. Its purpose is to allow the enabling of subsets of messages within one tool.

Debug messages are enabled with the tcl command: set_debug_level <tool> <group> <level>


The metrics logging uses a more restricted API since JSON only supports specific types. There are a set of overloaded methods of the form:

metric(ToolId tool,
       const std::string_view metric,
       <type> value)

where <type> can be int, double, string, or bool. This will result in the generated JSON:

"<tool>-<metric>" : value

String values will be enclosed in double-quotes automatically.

Converting to Logger#

The error functions in include/openroad/Error.hh should no longer be included or used. Use the corresponding logger functions.

All uses of the tcl functions ord::error and ord::warn should be updated call the utl::error/warn with a tool ID and message ID. For compatibility these are defaulted to UKN and 0000 until they are updated.

Regression tests should not have any UKN-0000 messages in their ok files. A simple grep should indicate that you still have pending calls to pre-logger error/warn functions.

The cmake file for the tool must also be updated to include spdlog in the link libraries so it can find the header files if they are not in the normal system directories.


At UCSD, is an example of this problem; it has an ancient version of spdlog in ‘/usr/include/spdlog’. Use module to install spdlog 1.8.1 on and check your build there.


Useful Information#

As tool developers, we can also choose to include useful information to the end user - be it in the form on debugging tips, or solutions to fix the errors/warnings. We compile a list of such errors in this table. The good thing about this page is the ability to encode rich formatting using Markdown, enabling you to convey more information than what can be said from the limited messages in code.

To format the information, refer to this sample GRT information file. In addition, make sure you create the corresponding docs/messages folder under the tool folder, before creating your Markdown file with the corresponding NUM.

cd src/<tool> && mkdir -p doc/messages
cd doc/messages && touch <NUM>.md

OpenROAD Tool List#

A full list of tool namespaces can be found here.