Skip to content

Commit

Permalink
Copy console output into a file
Browse files Browse the repository at this point in the history
Currently Qt frontend only, can be activated by passing -l/--log option:
celestia-qt --log /tmp/celestia.log
  • Loading branch information
375gnu committed Jan 14, 2021
1 parent 6b512f5 commit 18c5126
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 5 deletions.
21 changes: 20 additions & 1 deletion src/celestia/celestiacore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ CelestiaCore::CelestiaCore() :
#endif
m_scriptMaps(new ScriptMaps()),
oldFOV(stdFOV),
console(new Console(*renderer, 200, 120))
console(new Console(*renderer, 200, 120)),
m_tee(std::cout, std::cerr)
{

for (int i = 0; i < KeyCount; i++)
Expand All @@ -172,6 +173,9 @@ CelestiaCore::~CelestiaCore()

delete timer;
delete renderer;

if (m_logfile.good())
m_logfile.close();
}

void CelestiaCore::readFavoritesFile()
Expand Down Expand Up @@ -4666,3 +4670,18 @@ bool CelestiaCore::saveScreenShot(const fs::path& filename, ContentType type) co

return false;
}

void CelestiaCore::setLogFile(fs::path &fn)
{
m_logfile = std::ofstream(fn.string());
if (m_logfile.good())
{
m_tee = teestream(m_logfile, *console);
clog.rdbuf(m_tee.rdbuf());
cerr.rdbuf(m_tee.rdbuf());
}
else
{
fmt::fprintf(cerr, "Unable to open log file %s\n", fn);
}
}
6 changes: 6 additions & 0 deletions src/celestia/celestiacore.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#ifndef _CELESTIACORE_H_
#define _CELESTIACORE_H_

#include <fstream>
#include <celutil/filetype.h>
#include <celutil/timer.h>
#include <celutil/watcher.h>
Expand All @@ -22,6 +23,7 @@
#include <celengine/simulation.h>
#include <celengine/overlayimage.h>
#include <celengine/viewporteffect.h>
#include <celutil/tee.h>
#include "configfile.h"
#include "favorites.h"
#include "destination.h"
Expand Down Expand Up @@ -299,6 +301,8 @@ class CelestiaCore // : public Watchable<CelestiaCore>

void notifyWatchers(int);

void setLogFile(fs::path&);

class Alerter
{
public:
Expand Down Expand Up @@ -506,6 +510,8 @@ class CelestiaCore // : public Watchable<CelestiaCore>
string selectionNames;

std::unique_ptr<Console> console;
std::ofstream m_logfile;
teestream m_tee;

#ifdef CELX
friend View* getViewByObserver(CelestiaCore*, Observer*);
Expand Down
11 changes: 9 additions & 2 deletions src/celestia/qt/qtappwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ CelestiaAppWindow::~CelestiaAppWindow()


void CelestiaAppWindow::init(const QString& qConfigFileName,
const QStringList& qExtrasDirectories)
const QStringList& qExtrasDirectories,
const QString& logFilename)
{
QString celestia_data_dir = QString::fromLocal8Bit(::getenv("CELESTIA_DATA_DIR"));

Expand Down Expand Up @@ -236,6 +237,12 @@ void CelestiaAppWindow::init(const QString& qConfigFileName,

setWindowIcon(QIcon(":/icons/celestia.png"));

if (!logFilename.isEmpty())
{
fs::path fn(logFilename.toStdString());
m_appCore->setLogFile(fn);
}

if (!m_appCore->initSimulation(configFileName,
extrasDirectories,
progress))
Expand All @@ -261,7 +268,7 @@ void CelestiaAppWindow::init(const QString& qConfigFileName,
if (!gl::init() || !gl::checkVersion(gl::GL_2_1))
{
QMessageBox::critical(0, "Celestia", _("Celestia was unable to initialize OpenGL 2.1."));
exit(1);
exit(1);
}

m_appCore->setCursorHandler(glWidget);
Expand Down
3 changes: 2 additions & 1 deletion src/celestia/qt/qtappwin.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class CelestiaAppWindow : public QMainWindow, public CelestiaCore::ContextMenuHa
~CelestiaAppWindow();

void init(const QString& configFileName,
const QStringList& extrasDirectories);
const QStringList& extrasDirectories,
const QString& logFilename);

void readSettings();
void writeSettings();
Expand Down
13 changes: 12 additions & 1 deletion src/celestia/qt/qtmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ using namespace std;
static bool startFullscreen = false;
static bool runOnce = false;
static QString startURL;
static QString logFilename;
static QString startDirectory;
static QString startScript;
static QStringList extrasDirectories;
Expand Down Expand Up @@ -111,7 +112,7 @@ int main(int argc, char *argv[])
QObject::connect(&window, SIGNAL(progressUpdate(const QString&, int, const QColor&)),
&splash, SLOT(showMessage(const QString&, int, const QColor&)));

window.init(configFileName, extrasDirectories);
window.init(configFileName, extrasDirectories, logFilename);
window.show();

splash.finish(&window);
Expand Down Expand Up @@ -199,6 +200,16 @@ bool ParseCommandLine()
{
skipSplashScreen = true;
}
else if (args.at(i) == "-l" || args.at(i) == "--log")
{
if (isLastArg)
{
CommandLineError("A filename expected after --log/-l");
return false;
}
i++;
logFilename = args.at(i);
}
else
{
string buf = fmt::sprintf("Invalid command line option '%s'", args.at(i).toUtf8().data());
Expand Down
96 changes: 96 additions & 0 deletions src/celutil/tee.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// tee.h
//
// Copyright (C) 2009, Thomas Guest <[email protected]>
// 2021, the Celestia Development Team
//
// Tee stream implementation based on Thomas Guest post published at
// http://wordaligned.org/articles/cpp-streambufs
//
// This code is placed in the public domain.

#pragma once

#include <streambuf>

template <typename char_type,
typename traits = std::char_traits<char_type>>
class basic_teebuf :
public std::basic_streambuf<char_type, traits>
{
public:
typedef typename traits::int_type int_type;
typedef std::basic_streambuf<char_type, traits> streambuf_type;

// Construct a streambuf which tees output to both input
// streambufs.
basic_teebuf(streambuf_type *sb1,
streambuf_type *sb2) :
sb1(sb1),
sb2(sb2)
{}

basic_teebuf() = delete;
~basic_teebuf() = default;
basic_teebuf(const basic_teebuf&) = default;
basic_teebuf(basic_teebuf&&) = default;
basic_teebuf& operator=(const basic_teebuf&) = default;
basic_teebuf& operator=(basic_teebuf&&) = default;

private:
int_type overflow(int_type c) override
{
const auto eof = traits::eof();

if (traits::eq_int_type(c, eof))
return traits::not_eof(c);

const auto ch = traits::to_char_type(c);
const auto r1 = sb1->sputc(ch);
const auto r2 = sb2->sputc(ch);

return traits::eq_int_type(r1, eof) || traits::eq_int_type(r2, eof) ? eof : c;
}

int sync() override
{
const auto r1 = sb1->pubsync();
const auto r2 = sb2->pubsync();
return r1 == 0 && r2 == 0 ? 0 : -1;
}

streambuf_type *sb1;
streambuf_type *sb2;
};

typedef basic_teebuf<char> teebuf;
typedef basic_teebuf<wchar_t> wteebuf;


template <typename char_type,
typename traits = std::char_traits<char_type>>
class basic_teestream :
public std::basic_ostream<char_type, traits>
{
public:
typedef std::basic_ostream<char_type, traits> stream_type;

// Construct an ostream which tees output to the supplied
// ostreams.
basic_teestream(stream_type &o1, stream_type &o2) :
std::basic_ostream<char_type, traits>(&tbuf),
tbuf(o1.rdbuf(), o2.rdbuf())
{}

basic_teestream() = delete;
~basic_teestream() = default;
basic_teestream(const basic_teestream&) = default;
basic_teestream(basic_teestream&&) = default;
basic_teestream& operator=(const basic_teestream&) = default;
basic_teestream& operator=(basic_teestream&&) = default;

private:
basic_teebuf<char_type, traits> tbuf;
};

typedef basic_teestream<char> teestream;
typedef basic_teestream<wchar_t> wteestream;

0 comments on commit 18c5126

Please sign in to comment.