1
0
Fork 0

Error reporting: report Traffic errors

Also add logging to Sentry.io
This commit is contained in:
James Turner 2021-03-13 18:47:01 +00:00
parent 251b3aeb2b
commit fbbcc75229
6 changed files with 94 additions and 50 deletions

View file

@ -638,6 +638,9 @@ bool FGAIBase::init(ModelSearchOrder searchOrder)
_modeldata->addErrorContext("ai", _name); _modeldata->addErrorContext("ai", _name);
_modeldata->captureErrorContext("scenario-path"); _modeldata->captureErrorContext("scenario-path");
// set by FGAISchedule::createAIAircraft
_modeldata->captureErrorContext("traffic-aircraft-callsign");
if (_otype == otMultiplayer) { if (_otype == otMultiplayer) {
_modeldata->addErrorContext("multiplayer", getCallSign()); _modeldata->addErrorContext("multiplayer", getCallSign());
} }

View file

@ -38,6 +38,7 @@
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
#include <Main/globals.hxx> #include <Main/globals.hxx>
#include <Main/locale.hxx> #include <Main/locale.hxx>
#include <Main/sentryIntegration.hxx>
#include <Scripting/NasalClipboard.hxx> // clipboard access #include <Scripting/NasalClipboard.hxx> // clipboard access
using std::string; using std::string;
@ -70,7 +71,8 @@ enum class Aggregation {
FGData, FGData,
MultiPlayer, MultiPlayer,
Unknown, ///< error coudln't be attributed more specifcially Unknown, ///< error coudln't be attributed more specifcially
OutOfMemory ///< seperate category to give it a custom message OutOfMemory, ///< seperate category to give it a custom message
Traffic
}; };
// these should correspond to simgear::ErrorCode enum // these should correspond to simgear::ErrorCode enum
@ -111,7 +113,8 @@ string_list static_categoryIds = {
"error-category-fgdata", "error-category-fgdata",
"error-category-multiplayer", "error-category-multiplayer",
"error-category-unknown", "error-category-unknown",
"error-category-out-of-memory"}; "error-category-out-of-memory",
"error-category-traffic"};
class RecentLogCallback : public simgear::LogCallback class RecentLogCallback : public simgear::LogCallback
{ {
@ -234,6 +237,7 @@ public:
void collectError(simgear::LoadFailure type, simgear::ErrorCode code, const std::string& details, const sg_location& location) void collectError(simgear::LoadFailure type, simgear::ErrorCode code, const std::string& details, const sg_location& location)
{ {
SG_LOG(SG_GENERAL, SG_WARN, "Error:" << static_errorTypeIds.at(static_cast<int>(type)) << " from " << static_errorIds.at(static_cast<int>(code)) << "::" << details << "\n\t" << location.asString());
ErrorOcurrence occurrence{code, type, details, location, time(nullptr)}; ErrorOcurrence occurrence{code, type, details, location, time(nullptr)};
// snapshot the top of the context stacks into our occurence data // snapshot the top of the context stacks into our occurence data
@ -322,6 +326,8 @@ public:
}); });
assert(it != _aggregated.end()); assert(it != _aggregated.end());
_activeReportIndex = std::distance(_aggregated.begin(), it); _activeReportIndex = std::distance(_aggregated.begin(), it);
flightgear::sentryReportUserError(static_categoryIds.at(catId), detailsTextStream.str());
} }
void writeReportToStream(const AggregateReport& report, std::ostream& os) const; void writeReportToStream(const AggregateReport& report, std::ostream& os) const;
@ -355,6 +361,16 @@ auto ErrorReporter::ErrorReporterPrivate::getAggregateForOccurence(const ErrorRe
return getAggregate(Aggregation::MultiPlayer, {}); return getAggregate(Aggregation::MultiPlayer, {});
} }
// traffic cases: need to handle errors in the traffic files (schedule, rwyuse)
// but also errors loading aircraft models associated with traffic
if (oc.code == simgear::ErrorCode::AITrafficSchedule) {
return getAggregate(Aggregation::Traffic, {});
}
if (oc.hasContextKey("traffic-aircraft-callsign")) {
return getAggregate(Aggregation::Traffic, {});
}
// all TerraSync coded errors go there: this is errors for the // all TerraSync coded errors go there: this is errors for the
// actual download process (eg, failed to write to disk) // actual download process (eg, failed to write to disk)
if (oc.code == simgear::ErrorCode::TerraSync) { if (oc.code == simgear::ErrorCode::TerraSync) {

View file

@ -485,6 +485,26 @@ void sentryThreadReportXMLErrors(bool report)
perThread_reportXMLParseErrors = report; perThread_reportXMLParseErrors = report;
} }
void sentryReportUserError(const std::string& aggregate, const std::string& details)
{
if (!static_sentryEnabled)
return;
sentry_value_t sentryMessage = sentry_value_new_object();
sentry_value_set_by_key(sentryMessage, "type", sentry_value_new_string("Error"));
sentry_value_t info = sentry_value_new_object();
sentry_value_set_by_key(info, "details", sentry_value_new_string(details.c_str()));
sentry_set_context("what", info);
sentry_value_set_by_key(sentryMessage, "value", sentry_value_new_string(aggregate.c_str()));
sentry_value_t event = sentry_value_new_event();
sentry_value_set_by_key(event, "message", sentryMessage);
sentry_capture_event(event);
}
} // of namespace } // of namespace
#else #else
@ -535,6 +555,10 @@ void sentryThreadReportXMLErrors(bool)
{ {
} }
void sentryReportUserError(const std::string&, const std::string&)
{
}
} // of namespace } // of namespace
#endif #endif

View file

@ -43,6 +43,7 @@ void sentryReportException(const std::string& msg, const std::string& location =
void sentryReportFatalError(const std::string& msg, const std::string& more = {}); void sentryReportFatalError(const std::string& msg, const std::string& more = {});
void sentryReportUserError(const std::string& aggregate, const std::string& details);
/** /**
* @brief helper to allow per-thread supression of * @brief helper to allow per-thread supression of
* error reports based on XML parse/include errors. * error reports based on XML parse/include errors.

View file

@ -38,12 +38,13 @@
#include <algorithm> #include <algorithm>
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <simgear/sg_inlines.h> #include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/math/sg_geodesy.hxx> #include <simgear/math/sg_geodesy.hxx>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/sg_inlines.h>
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx>
#include <simgear/timing/sg_time.hxx> #include <simgear/timing/sg_time.hxx>
#include <simgear/xml/easyxml.hxx>
#include <AIModel/AIFlightPlan.hxx> #include <AIModel/AIFlightPlan.hxx>
#include <AIModel/AIManager.hxx> #include <AIModel/AIManager.hxx>
@ -380,6 +381,9 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
speedKnots, flightType, acType, speedKnots, flightType, acType,
airline)); airline));
if (fp->isValidPlan()) { if (fp->isValidPlan()) {
// set this here so it's available inside attach, which calls AIBase::init
simgear::ErrorReportContext ec{"traffic-aircraft-callsign", flight->getCallSign()};
aiAircraft->FGAIBase::setFlightPlan(std::move(fp)); aiAircraft->FGAIBase::setFlightPlan(std::move(fp));
globals->get_subsystem<FGAIManager>()->attach(aiAircraft); globals->get_subsystem<FGAIManager>()->attach(aiAircraft);
if (aiAircraft->_getProps()) { if (aiAircraft->_getProps()) {

View file

@ -323,7 +323,7 @@ private:
if (!FGAISchedule::validModelPath(mdl)) { if (!FGAISchedule::validModelPath(mdl)) {
missingModels.insert(mdl); missingModels.insert(mdl);
SG_LOG(SG_AI, SG_DEV_WARN, "TrafficMgr: Missing model path:" << mdl); simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::AITrafficSchedule, "Missing traffic model path:" + mdl, _currentFile);
requiredAircraft = homePort = ""; requiredAircraft = homePort = "";
return; return;
} }
@ -387,6 +387,7 @@ private:
SG_LOG(SG_AI, SG_DEBUG, "parsing traffic in:" << p); SG_LOG(SG_AI, SG_DEBUG, "parsing traffic in:" << p);
simgear::PathList trafficFiles = d2.children(simgear::Dir::TYPE_FILE, ".xml"); simgear::PathList trafficFiles = d2.children(simgear::Dir::TYPE_FILE, ".xml");
for (const auto& xml : trafficFiles) { for (const auto& xml : trafficFiles) {
_currentFile = xml;
try { try {
readXML(xml, *this); readXML(xml, *this);
if (_cancelThread) { if (_cancelThread) {
@ -395,7 +396,6 @@ private:
} catch (sg_exception& e) { } catch (sg_exception& e) {
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::AITrafficSchedule, simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::AITrafficSchedule,
"XML errors parsinng traffic:" + e.getFormattedMessage(), xml); "XML errors parsinng traffic:" + e.getFormattedMessage(), xml);
SG_LOG(SG_AI, SG_WARN, "XML error parsing traffic file:" << xml << "\n\t" << e.getFormattedMessage());
} }
} }
} // of sub-directories iteration } // of sub-directories iteration
@ -408,6 +408,7 @@ private:
bool _isFinished; bool _isFinished;
bool _cancelThread; bool _cancelThread;
simgear::PathList _trafficDirPaths; simgear::PathList _trafficDirPaths;
SGPath _currentFile;
// parser state // parser state
@ -828,14 +829,9 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
offset = atof(tokens[7].c_str());; offset = atof(tokens[7].c_str());;
if (!FGAISchedule::validModelPath(model)) { if (!FGAISchedule::validModelPath(model)) {
SG_LOG(SG_AI, SG_WARN, "TrafficMgr: Missing model path:" << simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::AITrafficSchedule, "Missing traffic model path:" + model, infileName);
model << " from " << infileName);
} else { } else {
SG_LOG(SG_AI, SG_DEBUG, "Adding Aircraft" << model << " " << livery << " " << homePort << " " << registration << " " << flightReq << " " << isHeavy << " " << acType << " " << airline << " " << m_class << " " << FlightType << " " << radius << " " << offset);
SG_LOG(SG_AI, SG_INFO, "Adding Aircraft" << model << " " << livery << " " << homePort << " "
<< registration << " " << flightReq << " " << isHeavy
<< " " << acType << " " << airline << " " << m_class
<< " " << FlightType << " " << radius << " " << offset);
scheduledAircraft.push_back(new FGAISchedule(model, scheduledAircraft.push_back(new FGAISchedule(model,
livery, livery,
homePort, homePort,