Add a new logging_file implementation

This adds a new logging_file subclass of ui_file.  This new subclass
handles the details of logging, by consulting the relevant globals.

I think a dependency on globals is warranted here, because the logging
settings themselves are global.

The idea of this approach is that rather than modifying the output
pipeline in response to logging commands, a logging_file will simply
always be in the pipeline, and will then react to the appropriate
settings.  ("Appropriate" because there are tests that the logger
doesn't immediately react to changes, so it captures settings at the
moment logging starts.)

The new code isn't actually used yet -- nothing in this patch
constructs a logging_file.  It's separate for easier review.

Approved-By: Andrew Burgess <aburgess@redhat.com>
This commit is contained in:
Tom Tromey 2025-12-06 15:35:24 -06:00
parent 0391f70c7d
commit aed0772e66
2 changed files with 201 additions and 0 deletions

View file

@ -20,6 +20,7 @@
#include "cli/cli-cmds.h"
#include "ui-out.h"
#include "interps.h"
#include "logging-file.h"
#include "cli/cli-style.h"
#include "cli/cli-decode.h"
@ -61,6 +62,9 @@ show_logging_overwrite (struct ui_file *file, int from_tty,
gdb_printf (file, _("off: Logging appends to the log file.\n"));
}
/* The current log file, or nullptr if none. */
static ui_file_up log_file;
/* Value as configured by the user. */
static bool logging_redirect;
static bool debug_redirect;
@ -96,6 +100,119 @@ show_logging_debug_redirect (struct ui_file *file, int from_tty,
_("off: Debug output will go to both the screen and the log file.\n"));
}
/* Values as used by the logging_file implementation. These are
separate and only set when logging is enabled, because historically
gdb required you to disable and re-enable logging to change these
settings. */
static bool logging_redirect_for_file;
static bool debug_redirect_for_file;
/* See logging-file.h. */
template<typename T>
bool
logging_file<T>::ordinary_output () const
{
if (log_file == nullptr)
return true;
if (logging_redirect_for_file)
return false;
if (debug_redirect_for_file)
return !m_for_stdlog;
return true;
}
/* See logging-file.h. */
template<typename T>
void
logging_file<T>::flush ()
{
if (log_file != nullptr)
log_file->flush ();
/* Always flushing seems fine. */
m_out->flush ();
}
/* See logging-file.h. */
template<typename T>
bool
logging_file<T>::can_page () const
{
/* If all output is redirected, do not page. */
if (!ordinary_output ())
return false;
/* In other cases, paging happens if the underlying stream can
page. */
return m_out->can_page ();
}
/* See logging-file.h. */
template<typename T>
void
logging_file<T>::write (const char *buf, long length_buf)
{
if (log_file != nullptr)
log_file->write (buf, length_buf);
if (ordinary_output ())
m_out->write (buf, length_buf);
}
/* See logging-file.h. */
template<typename T>
void
logging_file<T>::write_async_safe (const char *buf, long length_buf)
{
if (log_file != nullptr)
log_file->write_async_safe (buf, length_buf);
if (ordinary_output ())
m_out->write_async_safe (buf, length_buf);
}
/* See logging-file.h. */
template<typename T>
void
logging_file<T>::puts (const char *linebuffer)
{
if (log_file != nullptr)
log_file->puts (linebuffer);
if (ordinary_output ())
m_out->puts (linebuffer);
}
/* See logging-file.h. */
template<typename T>
void
logging_file<T>::emit_style_escape (const ui_file_style &style)
{
if (log_file != nullptr)
log_file->emit_style_escape (style);
if (ordinary_output ())
m_out->emit_style_escape (style);
}
/* See logging-file.h. */
template<typename T>
void
logging_file<T>::puts_unfiltered (const char *str)
{
if (log_file != nullptr)
log_file->puts_unfiltered (str);
if (ordinary_output ())
m_out->puts_unfiltered (str);
}
/* The available instantiations of logging_file. */
template class logging_file<ui_file *>;
template class logging_file<ui_file_up>;
/* If we've pushed output files, close them and pop them. */
static void
pop_output_files (void)
@ -141,6 +258,8 @@ handle_redirections (int from_tty)
}
saved_filename = logging_filename;
logging_redirect_for_file = logging_redirect;
debug_redirect_for_file = debug_redirect;
/* Let the interpreter do anything it needs. */
current_interp_set_logging (std::move (log), logging_redirect,

82
gdb/logging-file.h Normal file
View file

@ -0,0 +1,82 @@
/* Copyright (C) 2025, 2026 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDB_LOGGING_FILE_H
#define GDB_LOGGING_FILE_H
#include "ui-file.h"
/* A ui_file implementation that optionally writes its output to a
second logging stream. Whether logging is actually done depends on
the user's logging settings. The precise underlying ui_file type
is a template parameter, so that either owning or non-owning
instances can be made. */
template<typename T>
class logging_file : public ui_file
{
public:
/* This wraps another stream. Whether or not output actually goes
to that stream depends on the redirection settings. FOR_STDLOG
should only be set for a stream intended by use as gdb_stdlog;
this is used to implement the "debug redirect" feature. */
logging_file (T out, bool for_stdlog = false)
: m_out (std::move (out)),
m_for_stdlog (for_stdlog)
{
}
void write (const char *buf, long length_buf) override;
void write_async_safe (const char *buf, long length_buf) override;
void puts (const char *) override;
void flush () override;
bool can_page () const override;
void emit_style_escape (const ui_file_style &style) override;
void puts_unfiltered (const char *str) override;
bool isatty () override
{
/* Defer to the wrapped file. */
return m_out->isatty ();
}
bool term_out () override
{
/* Defer to the wrapped file. */
return m_out->term_out ();
}
bool can_emit_style_escape () override
{
/* Defer to the wrapped file. */
return m_out->can_emit_style_escape ();
}
private:
/* A helper function that returns true if output should go to
M_OUT. */
bool ordinary_output () const;
/* The underlying file. */
T m_out;
/* True if this stream is used for gdb_stdlog. This is used to
implement the debug redirect feature. */
bool m_for_stdlog;
};
#endif /* GDB_LOGGING_FILE_H */