Added new logging module.
This commit is contained in:
parent
9ff8951be6
commit
c22018db05
5 changed files with 260 additions and 0 deletions
75
docs-mini/README.logging
Normal file
75
docs-mini/README.logging
Normal file
|
@ -0,0 +1,75 @@
|
|||
Logging in FlightGear
|
||||
---------------------
|
||||
|
||||
[Note: JSBSim also has its own independent logging facilities, which
|
||||
are not discussed here.]
|
||||
|
||||
FlightGear can log any property values at any interval to one or more
|
||||
CSV files (which can be read and graphed using spreadsheets like
|
||||
Gnumeric or Excel). Logging is defined in the '/logging' subbranch of
|
||||
the main property tree; under '/logging', each '/log' subbranch
|
||||
defines a separate log with its own output file and interval. Here is
|
||||
a simple example that logs the rudder and aileron settings every
|
||||
second (1000ms) to the file steering.csv:
|
||||
|
||||
<logging>
|
||||
<log>
|
||||
<filename>steering.csv</filename>
|
||||
<interval-ms>1000</interval-ms>
|
||||
<entry>
|
||||
<title>Rudder</title>
|
||||
<property>/controls/rudder</property>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>Ailerons</title>
|
||||
<property>/controls/aileron</property>
|
||||
</entry>
|
||||
</log>
|
||||
</logging>
|
||||
|
||||
Each 'log' subbranch contains an optional 'filename' property
|
||||
(defaults to "fg_log.csv"), an optional 'interval-ms' property
|
||||
(defaults to 0, which logs every frame), and a series of 'entry'
|
||||
subbranches.
|
||||
|
||||
Each 'entry' subbranch contains a 'property' property specifying the
|
||||
name of the property to be logged, and an optional 'title' property
|
||||
specifying the title to use in the CSV file (defaults to the full path
|
||||
of the property). The elapsed time in milliseconds since the start of
|
||||
the simulation is always included as the first entry with the title
|
||||
"Time", so there is no need to include it explicitly.
|
||||
|
||||
Here's a sample of the logging output for the above log:
|
||||
|
||||
Time,Rudder,Ailerons
|
||||
6522,0.000000,0.000000
|
||||
7668,-0.000000,0.000000
|
||||
8702,-0.000000,0.000000
|
||||
9705,-0.000000,0.000000
|
||||
10784,-0.000000,0.000000
|
||||
11792,-0.000000,0.000000
|
||||
12808,-0.000000,-0.210000
|
||||
13826,-0.000000,-0.344000
|
||||
14881,-0.000000,-0.066000
|
||||
15901,-0.000000,-0.806000
|
||||
16943,-0.000000,-0.936000
|
||||
17965,-0.000000,-0.534000
|
||||
19013,-0.000000,-0.294000
|
||||
20044,-0.000000,0.270000
|
||||
21090,-0.000000,-1.000000
|
||||
22097,-0.000000,-0.168000
|
||||
|
||||
Note that the requested interval is only a minimum; most of the time,
|
||||
the actual interval is slightly longer than the requested one.
|
||||
|
||||
The easiest way for an end-user to define logs is to put the log in a
|
||||
separate XML file (usually under the user's home directory), then
|
||||
refer to it using the --config option, like this:
|
||||
|
||||
fgfs --config=log-config.xml
|
||||
|
||||
The output log files are always relative to the current directory.
|
||||
|
||||
--
|
||||
|
||||
David Megginson, 2002-03-12
|
|
@ -47,6 +47,7 @@ fgfs_SOURCES = \
|
|||
fg_props.cxx fg_props.hxx \
|
||||
fgfs.cxx fgfs.hxx \
|
||||
globals.cxx globals.hxx \
|
||||
logger.cxx logger.hxx \
|
||||
model.cxx model.hxx \
|
||||
options.cxx options.hxx \
|
||||
splash.cxx splash.hxx \
|
||||
|
|
|
@ -116,6 +116,7 @@
|
|||
#include "fg_props.hxx"
|
||||
#include "options.hxx"
|
||||
#include "globals.hxx"
|
||||
#include "logger.hxx"
|
||||
#include "viewmgr.hxx"
|
||||
|
||||
#if defined(FX) && defined(XMESA)
|
||||
|
@ -779,6 +780,14 @@ bool fgInitSubsystems( void ) {
|
|||
fgEVENT::FG_EVENT_READY, 30000 );
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialize the logger.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
globals->set_logger(new FGLogger);
|
||||
globals->get_logger()->init();
|
||||
globals->get_logger()->bind();
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialize the local time subsystem.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
110
src/Main/logger.cxx
Normal file
110
src/Main/logger.cxx
Normal file
|
@ -0,0 +1,110 @@
|
|||
// logger.cxx - log properties.
|
||||
// Written by David Megginson, started 2002.
|
||||
//
|
||||
// This file is in the Public Domain, and comes with no warranty.
|
||||
|
||||
#include "logger.hxx"
|
||||
|
||||
#include <fstream>
|
||||
SG_USING_STD(ofstream);
|
||||
SG_USING_STD(endl);
|
||||
|
||||
#include <string>
|
||||
SG_USING_STD(string);
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "fg_props.hxx"
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGLogger
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGLogger::FGLogger ()
|
||||
{
|
||||
}
|
||||
|
||||
FGLogger::~FGLogger ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FGLogger::init ()
|
||||
{
|
||||
SGPropertyNode * logging = fgGetNode("/logging");
|
||||
if (logging == 0)
|
||||
return;
|
||||
|
||||
vector<SGPropertyNode *> children = logging->getChildren("log");
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
_logs.push_back(Log());
|
||||
Log &log = _logs[_logs.size()-1];
|
||||
SGPropertyNode * child = children[i];
|
||||
string filename = child->getStringValue("filename", "fg_log.csv");
|
||||
log.interval_ms = child->getLongValue("interval-ms", 0);
|
||||
log.output = new ofstream(filename.c_str());
|
||||
if (!log.output) {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Cannot write log to " << filename);
|
||||
continue;
|
||||
}
|
||||
vector<SGPropertyNode *> entries = child->getChildren("entry");
|
||||
(*log.output) << "Time";
|
||||
for (int j = 0; j < entries.size(); j++) {
|
||||
SGPropertyNode * entry = entries[j];
|
||||
SGPropertyNode * node =
|
||||
fgGetNode(entry->getStringValue("property"), true);
|
||||
log.nodes.push_back(node);
|
||||
(*log.output) << ','
|
||||
<< entry->getStringValue("title", node->getPath());
|
||||
}
|
||||
(*log.output) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FGLogger::bind ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FGLogger::unbind ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FGLogger::update (int dt)
|
||||
{
|
||||
long elapsed_ms = globals->get_elapsed_time_ms();
|
||||
for (int i = 0; i < _logs.size(); i++) {
|
||||
if ((elapsed_ms - _logs[i].last_time_ms) >= _logs[i].interval_ms) {
|
||||
_logs[i].last_time_ms = elapsed_ms;
|
||||
(*_logs[i].output) << globals->get_elapsed_time_ms();
|
||||
for (int j = 0; j < _logs[i].nodes.size(); j++) {
|
||||
(*_logs[i].output) << ',' << _logs[i].nodes[j]->getStringValue();
|
||||
}
|
||||
(*_logs[i].output) << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGLogger::Log
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGLogger::Log::Log ()
|
||||
: output(0),
|
||||
interval_ms(0),
|
||||
last_time_ms(-99999999999999L)
|
||||
{
|
||||
}
|
||||
|
||||
FGLogger::Log::~Log ()
|
||||
{
|
||||
delete output;
|
||||
}
|
||||
|
||||
// end of logger.cxx
|
65
src/Main/logger.hxx
Normal file
65
src/Main/logger.hxx
Normal file
|
@ -0,0 +1,65 @@
|
|||
// logger.hxx - log properties.
|
||||
// Written by David Megginson, started 2002.
|
||||
//
|
||||
// This file is in the Public Domain, and comes with no warranty.
|
||||
|
||||
#ifndef __LOGGER_HXX
|
||||
#define __LOGGER_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/exception.hxx>
|
||||
#include <simgear/misc/props.hxx>
|
||||
|
||||
#include <iostream>
|
||||
SG_USING_STD(ostream);
|
||||
|
||||
#include <vector>
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include "fgfs.hxx"
|
||||
|
||||
|
||||
/**
|
||||
* Log any property values to any number of CSV files.
|
||||
*/
|
||||
class FGLogger : public FGSubsystem
|
||||
{
|
||||
public:
|
||||
|
||||
FGLogger ();
|
||||
virtual ~FGLogger ();
|
||||
|
||||
// Implementation of FGSubsystem
|
||||
virtual void init ();
|
||||
virtual void bind ();
|
||||
virtual void unbind ();
|
||||
virtual void update (int dt);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* A single instance of a log file (the logger can contain many).
|
||||
*/
|
||||
struct Log {
|
||||
Log ();
|
||||
virtual ~Log ();
|
||||
vector<SGPropertyNode *> nodes;
|
||||
ostream * output;
|
||||
long interval_ms;
|
||||
long last_time_ms;
|
||||
};
|
||||
|
||||
vector<Log> _logs;
|
||||
|
||||
};
|
||||
|
||||
#endif // __LOGGER_HXX
|
Loading…
Reference in a new issue