.. SPDX-FileCopyrightText: 2026 James Turner .. SPDX-License-Identifier: GPL-2.0-or-later Logging infrastructure ====================== SimGear provides a centralised logging infrastrucutre with runtime configuration of logging levels according to categories. Multiple log consumers can be installed, each with their own logging settings. Log consumers (:cpp:class:`simgear::LogCallback`) run in a dedicated thread, so that their IO doesn't block threads creating log entries. This allows for safe disk or network IO in a log consumer. Messages are passed from arbitrary threads via a thread-safe queue, so the logging consumers see atomic, time-stamped entries. All consumers process an entry, before the next entry is processed. Various *console* consumers are defined, linked to standard output. The exact behaviour of these is platform-dependent: the POSIX platforms (incuding macOS) simply output to ``stderr``, while on Windows output to the debug console (`OutputDebugStringA `__) is supported by setting the environment variable :term:`SG_WINDEBUG` to something true-ish, and otherwise, the Windows terminal console is used. By default FlightGear also logs to a file in :term:`FG_HOME`, called :file:`fgfs.log`, which is rotated on each startup. This file logs by default at level ``INFO``, to balance size of the files, with usefulness of post-hoc investigation of problems. Runtime Configuration --------------------- The ``log-level`` command allows changing logging settings dynmically. The follows arguments are supported: tag indicates which callback(s) to modify. Default value is ``console`` all priority value for the ``SG_ALL`` category priority value for the category ````. This can be repeated for multiple categories. Additional file logs can be created using the ``log-to-file`` command. The property :fgprop:`/sim/log-file-line` configures if log entries include the file and source line of the log entry or not. Implementation Details ---------------------- To avoid locking overhead on the common path, the log consumer thread is stopped and restarted when configuration changes occur. This is effective since configuration changes are very rare, and the logging data is otherwise read-only and hence thread-safe. The logging frontend is the ``SG_LOG`` macro, which calls the :cpp:func:`logstream::would_log()` predicate, and if this passes, the :cpp:func:`logstream::log` method. :cpp:func:`logstream::would_log` allows fast rejection of non-logged entries before the expensive formatting incurred by `std::ostringstream `__ takes place. Internally, :cpp:func:`logstream::would_log()` uses the lowest (most permissive) log level of all the registered callbacks. This means that if no callback is interested in say ``SG_DEBUG`` messages, they will be skipped before the work of building the message occurs. The current filtering state of a log callback is tracked via the :cpp:class:`simgear::LogLevels` class, which has a threshold priority for each defined category. Categories with no explicit priority use the ``SG_ALL`` priority automatically. Startup Logging --------------- During startup, log messages are buffered in the logging system, so that the full log contents are available when additional log consumers are registered. Once the main loop reaches initialization stage 1000, startup logging is disabled via a call to :cpp:func:`logstream::setStartupLoggingEnabled`, and the buffer is cleared. Buffered log callbacks ---------------------- Various places created a :cpp:class:`simgear::BufferedLogCallback` to collect messages of a certain category, and show them in a UI. This is used for the `TerraSync` log (collects TerraSync and scenery messages), and for the Nasal console. The callback handles thread-safety, and the standard filtering mechanism means only the requested subset of messages is collected. Log Delta --------- .. todo:: Document and discuss the log delta system. .. toctree:: :maxdepth: 2 :caption: Classes classes/logstream classes/LogLevels classes/LogCallback classes/BufferedLogCallback