Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:37

0001 
0002 #include "JInspector.h"
0003 #include <JANA/JEventSource.h>
0004 #include <stack>
0005 #include <JANA/Utils/JTablePrinter.h>
0006 
0007 
0008 JInspector::JInspector(const JEvent* event) : m_event(event) {}
0009 
0010 void JInspector::Reset() {
0011     m_indexes_built = false;
0012     m_factories.clear();
0013     m_factory_index.clear();
0014     m_discrepancies.clear();
0015 }
0016 
0017 void JInspector::SetDiscrepancies(std::set<std::string>&& diverging_factory_keys) {
0018     m_discrepancies = std::move(diverging_factory_keys);
0019 }
0020 
0021 void JInspector::BuildIndices() {
0022     if (m_indexes_built) return;
0023     for (auto fac: m_event->GetFactorySet()->GetAllFactories()) {
0024         m_factories.push_back(fac);
0025     }
0026     std::sort(m_factories.begin(), m_factories.end(), [](const JFactory* first, const JFactory* second){
0027         return std::make_pair(first->GetObjectName(), first->GetTag()) <
0028                std::make_pair(second->GetObjectName(), second->GetTag());});
0029 
0030     int i = 0;
0031     for (auto fac : m_factories) {
0032         std::string key = MakeFactoryKey(fac->GetObjectName(), fac->GetTag());
0033         std::pair<int, const JFactory*> value = {i++, fac};
0034         m_factory_index.insert({key, value});
0035         m_factory_index.insert({std::to_string(i), value});
0036     }
0037     m_indexes_built = true;
0038 }
0039 
0040 std::vector<const JObject*> JInspector::FindAllAncestors(const JObject* root) {
0041     std::vector<const JObject*> all_ancestors;
0042     std::stack<const JObject*> to_visit;
0043     to_visit.push(root);
0044     while (!to_visit.empty()) {
0045         auto current_obj = to_visit.top();
0046         to_visit.pop();
0047         all_ancestors.push_back(current_obj);
0048         std::vector<const JObject*> current_ancestors;
0049         current_obj->GetT<JObject>(current_ancestors);
0050         for (auto obj : current_ancestors) {
0051             to_visit.push(obj);
0052         }
0053     }
0054     return all_ancestors;
0055 }
0056 
0057 std::tuple<JFactory*, size_t, size_t> JInspector::LocateObject(const JEvent& event, const JObject* obj) {
0058     auto objName = obj->className();
0059     size_t fac_idx = 0;
0060     for (auto fac : event.GetAllFactories()) {
0061         if (fac->GetObjectName() == objName) {
0062             size_t obj_idx = 0;
0063             for (auto o : fac->GetAs<JObject>()) { // Won't trigger factory creation if it hasn't already happened
0064                 if (obj == o) {
0065                     return std::make_tuple(fac, fac_idx, obj_idx);
0066                 }
0067                 obj_idx++;
0068             }
0069         }
0070         fac_idx++;
0071     }
0072     return std::make_tuple(nullptr, -1, -1);
0073 }
0074 
0075 void JInspector::PrintEvent() {
0076     ToText(m_event, m_format==Format::Json, m_out);
0077 }
0078 void JInspector::PrintFactories(int filter_level=0) {
0079     BuildIndices();
0080     ToText(m_factories, m_discrepancies, filter_level, m_format==Format::Json, m_out);
0081 }
0082 
0083 void JInspector::PrintObjects(std::string factory_key) {
0084     BuildIndices();
0085     auto result = m_factory_index.find(factory_key);
0086     if (result == m_factory_index.end()) {
0087         m_out << "(Error: Invalid factory name or index)\n";
0088         return;
0089     }
0090     auto fac = const_cast<JFactory*>(result->second.second);
0091     auto objs = fac->GetAs<JObject>();
0092     ToText(objs, m_format==Format::Json, m_out);
0093 }
0094 
0095 void JInspector::PrintFactoryDetails(std::string fac_key) {
0096     BuildIndices();
0097     auto result = m_factory_index.find(fac_key);
0098     if (result == m_factory_index.end()) {
0099         m_out << "(Error: Invalid factory name or index)\n";
0100         return;
0101     }
0102     auto fac = result->second.second;
0103     ToText(fac, m_format==Format::Json, m_out);
0104 }
0105 
0106 void JInspector::PrintObject(std::string fac_key, int object_idx) {
0107     BuildIndices();
0108     auto result = m_factory_index.find(fac_key);
0109     if (result == m_factory_index.end()) {
0110         m_out << "(Error: Invalid factory name or index)\n";
0111         return;
0112     }
0113     JFactory* fac = const_cast<JFactory*>(result->second.second);
0114     auto objs = fac->GetAs<JObject>();
0115     if ((size_t) object_idx >= objs.size()) {
0116         m_out << "(Error: Object index out of range)" << std::endl;
0117         return;
0118     }
0119     auto obj = objs[object_idx];
0120     ToText(obj, m_format==Format::Json, m_out);
0121 }
0122 std::string JInspector::MakeFactoryKey(std::string name, std::string tag) {
0123     std::ostringstream ss;
0124     ss << name;
0125     if (!tag.empty()) {
0126         ss << ":" << tag;
0127     }
0128     return ss.str();
0129 }
0130 
0131 void JInspector::PrintHelp() {
0132     m_out << "  -----------------------------------------" << std::endl;
0133     m_out << "  Available commands" << std::endl;
0134     m_out << "  -----------------------------------------" << std::endl;
0135     m_out << "  pe   PrintEvent" << std::endl;
0136     m_out << "  pf   PrintFactories [filter_level <- {0,1,2,3}]" << std::endl;
0137     m_out << "  pfd  PrintFactoryDetails fac_idx" << std::endl;
0138     m_out << "  po   PrintObjects fac_idx" << std::endl;
0139     m_out << "  po   PrintObject fac_idx obj_idx" << std::endl;
0140     m_out << "  pfp  PrintFactoryParents fac_idx" << std::endl;
0141     m_out << "  pop  PrintObjectParents fac_idx obj_idx" << std::endl;
0142     m_out << "  poa  PrintObjectAncestors fac_idx obj_idx" << std::endl;
0143     m_out << "  vt   ViewAsTable" << std::endl;
0144     m_out << "  vj   ViewAsJson" << std::endl;
0145     m_out << "  x    Exit" << std::endl;
0146     m_out << "  h    Help" << std::endl;
0147     m_out << "  -----------------------------------------" << std::endl;
0148 }
0149 void JInspector::ToText(const JEvent* event, bool asJson, std::ostream& out) {
0150     auto className = event->GetJEventSource()->GetTypeName();
0151     if (className.empty()) className = "(unknown)";
0152     if (asJson) {
0153         out << "{ \"run_number\": " << event->GetRunNumber();
0154         out << ", \"event_number\": " << event->GetEventNumber();
0155         out << ", \"source\": \"" << event->GetJEventSource()->GetResourceName();
0156         out << "\", \"class_name\": \"" << className;
0157         out << "\", \"is_sequential\": \"" << event->GetSequential() << "\"}";
0158         out << std::endl;
0159     }
0160     else {
0161         out << "Run number:   " << event->GetRunNumber() << std::endl;
0162         out << "Event number: " << event->GetEventNumber() << std::endl;
0163         out << "Event source: " << event->GetJEventSource()->GetResourceName() << std::endl;
0164         out << "Class name:   " << className << std::endl;
0165         out << "Sequential:   " << event->GetSequential() << std::endl;
0166     }
0167 }
0168 
0169 void JInspector::ToText(const JFactory* fac, bool asJson, std::ostream& out) {
0170 
0171     auto pluginName = fac->GetPluginName();
0172     if (pluginName.empty()) pluginName = "(no plugin)";
0173 
0174     auto factoryName = fac->GetFactoryName();
0175     // if (factoryName.empty()) factoryName = "(no name)";
0176 
0177     auto tag = fac->GetTag();
0178     if (tag.empty()) tag = "(no tag)";
0179 
0180     std::string creationStatus;
0181     switch (fac->GetCreationStatus()) {
0182         case JFactory::CreationStatus::NotCreatedYet: creationStatus = "NotCreatedYet"; break;
0183         case JFactory::CreationStatus::Created: creationStatus = "Created"; break;
0184         case JFactory::CreationStatus::Inserted: creationStatus = "Inserted"; break;
0185         case JFactory::CreationStatus::InsertedViaGetObjects: creationStatus = "InsertedViaGetObjects"; break;
0186         case JFactory::CreationStatus::NeverCreated: creationStatus = "NeverCreated"; break;
0187         default: creationStatus = "Unknown";
0188     }
0189 
0190     if (!asJson) {
0191         out << "Plugin name          " << pluginName << std::endl;
0192         // out << "Factory name         " << factoryName << std::endl;
0193         out << "Object name          " << fac->GetObjectName() << std::endl;
0194         out << "Tag                  " << tag << std::endl;
0195         out << "Creation status      " << creationStatus << std::endl;
0196         out << "Object count         " << fac->GetNumObjects() << std::endl;
0197         out << "Persistent flag      " << fac->TestFactoryFlag(JFactory::PERSISTENT) << std::endl;
0198         out << "NotObjectOwner flag  " << fac->TestFactoryFlag(JFactory::NOT_OBJECT_OWNER) << std::endl;
0199     }
0200     else {
0201         out << "{" << std::endl;
0202         out << "  \"plugin_name\":   \"" << pluginName << "\"," << std::endl;
0203         out << "  \"factory_name\":  \"" << factoryName << "\"," << std::endl;
0204         out << "  \"object_name\":   \"" << fac->GetObjectName() << "\"," << std::endl;
0205         out << "  \"tag\":           \"" << tag << "\"," << std::endl;
0206         out << "  \"creation\":      \"" << creationStatus << "\"," << std::endl;
0207         out << "  \"object_count\":  " << fac->GetNumObjects() << "," << std::endl;
0208         out << "  \"persistent\":    " << fac->TestFactoryFlag(JFactory::PERSISTENT) << "," << std::endl;
0209         out << "  \"not_obj_owner\": " << fac->TestFactoryFlag(JFactory::NOT_OBJECT_OWNER) << std::endl;
0210         out << "}" << std::endl;
0211     }
0212 }
0213 
0214 void JInspector::ToText(const std::vector<JFactory*>& factories, const std::set<std::string>& discrepancies, int filterlevel, bool asJson, std::ostream &out) {
0215     size_t idx = -1;
0216     if (!asJson) {
0217         JTablePrinter t;
0218         t.AddColumn("Index", JTablePrinter::Justify::Right);
0219         t.AddColumn("Object");
0220         t.AddColumn("Tag");
0221         t.AddColumn("Creation status");
0222         t.AddColumn("Object count", JTablePrinter::Justify::Right);
0223         t.AddColumn("Discrepancy", JTablePrinter::Justify::Right);
0224         for (auto fac : factories) {
0225             auto tag = fac->GetTag();
0226             if (tag.empty()) tag = "(no tag)";
0227             std::string creationStatus;
0228             switch (fac->GetCreationStatus()) {
0229                 case JFactory::CreationStatus::NotCreatedYet: creationStatus = "NotCreatedYet"; break;
0230                 case JFactory::CreationStatus::Created: creationStatus = "Created"; break;
0231                 case JFactory::CreationStatus::Inserted: creationStatus = "Inserted"; break;
0232                 case JFactory::CreationStatus::InsertedViaGetObjects: creationStatus = "InsertedViaGetObjects"; break;
0233                 case JFactory::CreationStatus::NeverCreated: creationStatus = "NeverCreated"; break;
0234                 default: creationStatus = "Unknown";
0235             }
0236             idx += 1;
0237             if (filterlevel > 0 && (fac->GetCreationStatus()==JFactory::CreationStatus::NeverCreated ||
0238                            fac->GetCreationStatus()==JFactory::CreationStatus::NotCreatedYet)) continue;
0239             if (filterlevel > 1 && (fac->GetNumObjects()== 0)) continue;
0240             if (filterlevel > 2 && (fac->GetCreationStatus()==JFactory::CreationStatus::Inserted ||
0241                                     fac->GetCreationStatus()==JFactory::CreationStatus::InsertedViaGetObjects)) continue;
0242 
0243             char discrepancy = ' ';
0244             auto key = MakeFactoryKey(fac->GetObjectName(), fac->GetTag());
0245             if (discrepancies.find(key) != discrepancies.end()) discrepancy = 'x';
0246 
0247             t | idx | fac->GetObjectName() | tag | creationStatus | fac->GetNumObjects() | discrepancy;
0248         }
0249         t.Render(out);
0250     }
0251     else {
0252         out << "{" << std::endl;
0253         for (auto fac : factories) {
0254             auto facName = fac->GetFactoryName();
0255             if (facName.empty()) facName = "null";
0256             auto tag = fac->GetTag();
0257             if (tag.empty()) tag = "null";
0258             out << "  " << idx++ << ": { \"factory_name\": ";
0259             if (fac->GetFactoryName().empty()) {
0260                 out << "null, ";
0261             }
0262             else {
0263                 out << "\"" << fac->GetFactoryName() << "\", ";
0264             }
0265             out << "\"object_name\": \"" << fac->GetObjectName() << "\", \"tag\": ";
0266             if (fac->GetTag().empty()) {
0267                 out << "null, ";
0268             }
0269             else {
0270                 out << "\"" << fac->GetTag() << "\", ";
0271             }
0272             out << "\"object_count\": " << fac->GetNumObjects();
0273             out << "}," << std::endl;
0274         }
0275         out << "}" << std::endl;
0276     }
0277 }
0278 
0279 void JInspector::ToText(std::vector<JObject*> objs, bool as_json, std::ostream& out) {
0280 
0281     if (objs.empty()) {
0282         out << "(No objects found)" << std::endl;
0283         return;
0284     }
0285     std::set<std::string> objnames;
0286     for (auto obj: objs) {
0287         objnames.insert(obj->className());
0288     }
0289     if (objnames.size() == 1) {
0290         out << *(objnames.begin()) << std::endl;
0291     }
0292     else {
0293         out << "{ ";
0294         for (auto name : objnames) {
0295             out << name << ",";
0296         }
0297         out << "}" << std::endl;
0298     }
0299     if (as_json) {
0300         out << "{" << std::endl;
0301         for (size_t i = 0; i < objs.size(); ++i) {
0302             auto obj = objs[i];
0303             JObjectSummary summary;
0304             obj->Summarize(summary);
0305             out << "  " << i << ":  {";
0306             for (auto& field : summary.get_fields()) {
0307                 out << "\"" << field.name << "\": \"" << field.value << "\", ";
0308             }
0309             out << "}" << std::endl;
0310         }
0311         out << "}" << std::endl;
0312     }
0313     else {
0314         JTablePrinter t;
0315         std::set<std::string> fieldnames_seen;
0316         std::vector<std::string> fieldnames_in_order;
0317         for (auto obj : objs) {
0318             JObjectSummary summary;
0319             obj->Summarize(summary);
0320             for (auto field : summary.get_fields()) {
0321                 if (fieldnames_seen.find(field.name) == fieldnames_seen.end()) {
0322                     fieldnames_in_order.push_back(field.name);
0323                     fieldnames_seen.insert(field.name);
0324                 }
0325             }
0326         }
0327         t.AddColumn("Index");
0328         for (auto fieldname : fieldnames_in_order) {
0329             t.AddColumn(fieldname);
0330         }
0331         for (size_t i = 0; i < objs.size(); ++i) {
0332             auto obj = objs[i];
0333             t | i;
0334             std::map<std::string, std::string> summary_map;
0335             JObjectSummary summary;
0336             obj->Summarize(summary);
0337             for (auto& field : summary.get_fields()) {
0338                 summary_map[field.name] = field.value;
0339             }
0340             for (auto& fieldname : fieldnames_in_order) {
0341                 auto result = summary_map.find(fieldname);
0342                 if (result == summary_map.end()) {
0343                     t | "(missing)";
0344                 }
0345                 else {
0346                     t | result->second;
0347                 }
0348             }
0349         }
0350         t.Render(out);
0351     }
0352 }
0353 
0354 void JInspector::ToText(const JObject* obj, bool asJson, std::ostream& out) {
0355     out << obj->className() << std::endl;
0356     JObjectSummary summary;
0357     obj->Summarize(summary);
0358     if (asJson) {
0359         out << "[" << std::endl;
0360         for (auto& field : summary.get_fields()) {
0361             out << "  { \"name\": \"" << field.name << "\", ";
0362             out << "\"value\": \"" << field.value << "\", ";
0363             out << "\"description\": \"" << field.description << "\" }" << std::endl;
0364         }
0365         out << "]" << std::endl;
0366     }
0367     else {
0368         JTablePrinter t;
0369         t.AddColumn("Field name");
0370         t.AddColumn("Value");
0371         t.AddColumn("Description");
0372         for (auto& field : summary.get_fields()) {
0373             t | field.name | field.value | field.description;
0374         }
0375         t.Render(out);
0376     }
0377 }
0378 
0379 void JInspector::PrintFactoryParents(std::string factory_idx) {
0380 
0381     bool callgraph_on = m_event->GetJCallGraphRecorder()->IsEnabled();
0382     if (!callgraph_on) {
0383         m_out << "(Error: Callgraph recording is currently disabled)" << std::endl;
0384     }
0385 
0386     BuildIndices();  // So that we can retrieve the integer index given the factory name/tag pair
0387     auto result = m_factory_index.find(factory_idx);
0388     if (result == m_factory_index.end()) {
0389         m_out << "(Error: Invalid factory name or index)\n";
0390         return;
0391     }
0392     auto fac = result->second.second;
0393     auto obj_name = fac->GetObjectName();
0394     auto fac_tag = fac->GetTag();
0395     if (fac_tag.empty()) {
0396         m_out << obj_name << std::endl;
0397     }
0398     else {
0399         m_out << obj_name << ":" << fac_tag << std::endl;
0400     }
0401 
0402     if (m_format != Format::Json) {
0403         JTablePrinter t;
0404         t.AddColumn("Index", JTablePrinter::Justify::Right);
0405         t.AddColumn("Object name");
0406         t.AddColumn("Tag");
0407         auto callgraph = m_event->GetJCallGraphRecorder()->GetCallGraph();
0408         bool found_anything = false;
0409         for (const auto& node : callgraph) {
0410             if ((node.caller_name == obj_name) && (node.caller_tag == fac_tag)) {
0411                 found_anything = true;
0412                 auto idx = m_factory_index[MakeFactoryKey(node.callee_name, node.callee_tag)].first;
0413                 auto tag = node.callee_tag;
0414                 if (tag.empty()) tag = "(no tag)";
0415                 t | idx | node.callee_name | tag;
0416             }
0417         }
0418         if (!found_anything) {
0419             m_out << "(No parents found)" << std::endl;
0420             return;
0421         }
0422         t.Render(m_out);
0423     }
0424     else {
0425         auto callgraph = m_event->GetJCallGraphRecorder()->GetCallGraph();
0426         bool found_anything = false;
0427         m_out << "[" << std::endl;
0428         for (const auto& node : callgraph) {
0429             if ((node.caller_name == obj_name) && (node.caller_tag == fac_tag)) {
0430                 found_anything = true;
0431                 auto idx = m_factory_index[MakeFactoryKey(node.callee_name, node.callee_tag)].first;
0432                 auto tag = node.callee_tag;
0433                 m_out << "  { \"index\": " << idx << ", \"object_name\": \"" << node.callee_name << "\", \"tag\": ";
0434                 if (tag.empty()) {
0435                     m_out << "null }," << std::endl;
0436                 }
0437                 else {
0438                     m_out << "\"" << tag << "\" }," << std::endl;
0439                 }
0440             }
0441         }
0442         m_out << "]" << std::endl;
0443         if (!found_anything) {
0444             m_out << "(No ancestors found)" << std::endl;
0445             return;
0446         }
0447     }
0448 }
0449 
0450 void JInspector::PrintObjectParents(std::string factory_key, int object_idx) {
0451 
0452     BuildIndices();  // So that we can retrieve the integer index given the factory name/tag pair
0453     auto result = m_factory_index.find(factory_key);
0454     if (result == m_factory_index.end()) {
0455         m_out << "(Error: Invalid factory name or index)\n";
0456         return;
0457     }
0458     auto fac = const_cast<JFactory*>(result->second.second);
0459     auto objs = fac->GetAs<JObject>();
0460     if ((size_t) object_idx >= objs.size()) {
0461         m_out << "(Error: Object index out of range)" << std::endl;
0462         return;
0463     }
0464     auto obj = objs[object_idx];
0465     m_out << obj->className() << std::endl;
0466     std::vector<const JObject*> parents;
0467     obj->GetT<JObject>(parents);
0468     if (parents.empty()) {
0469         m_out << "(No parents found)" << std::endl;
0470         return;
0471     }
0472 
0473     if (m_format == Format::Table) {
0474         JTablePrinter t;
0475         t.AddColumn("Object name");
0476         t.AddColumn("Tag");
0477         t.AddColumn("Factory Index", JTablePrinter::Justify::Right);
0478         t.AddColumn("Object Index", JTablePrinter::Justify::Right);
0479         t.AddColumn("Object contents");
0480         for (auto parent : parents) {
0481             JFactory* fac;
0482             size_t fac_idx;
0483             size_t obj_idx;
0484             std::tie(fac, fac_idx, obj_idx) = LocateObject(*m_event, parent);
0485             if (fac == nullptr) {
0486                 m_out << "(Error: Unable to find factory containing object with classname '" << obj->className() << "')" << std::endl;
0487                 continue;
0488             }
0489             JObjectSummary summary;
0490             parent->Summarize(summary);
0491 
0492             auto tag = fac->GetTag();
0493             if (tag.empty()) tag = "(no tag)";
0494             std::ostringstream objval;
0495             objval << "{";
0496             for (auto& field : summary.get_fields()) {
0497                 objval << field.name << ": " << field.value << ", ";
0498             }
0499             objval << "}";
0500 
0501             t | fac->GetObjectName() | tag | fac_idx | obj_idx | objval.str();
0502         }
0503         t.Render(m_out);
0504     }
0505     else {
0506         m_out << "[" << std::endl;
0507         for (auto ancestor : FindAllAncestors(obj)) {
0508             JFactory* fac;
0509             size_t fac_idx;
0510             size_t obj_idx;
0511             std::tie(fac, fac_idx, obj_idx) = LocateObject(*m_event, ancestor);
0512             if (fac == nullptr) {
0513                 m_out << "(Error: Unable to find factory containing object with classname '" << obj->className() << "')" << std::endl;
0514                 continue;
0515             }
0516             auto tag = fac->GetTag();
0517             if (tag.empty()) tag = "(no tag)";
0518 
0519             m_out << "  " << "{ " << std::endl << "    \"object_name\": \"" << fac->GetObjectName() << "\", ";
0520             if (tag.empty()) {
0521                 m_out << "\"tag\": null, ";
0522             }
0523             else {
0524                 m_out << "\"tag\": \"" << tag << "\", ";
0525             }
0526             m_out << "\"fac_index\": " << fac_idx << ", \"obj_index\": " << obj_idx << "," << std::endl;
0527             m_out << "    \"object_contents\": ";
0528 
0529             JObjectSummary summary;
0530             ancestor->Summarize(summary);
0531             m_out << "{";
0532             for (auto& field : summary.get_fields()) {
0533                 m_out << "\"" << field.name << "\": \"" << field.value << "\", ";
0534             }
0535             m_out << "}" << std::endl;
0536             m_out << "  }, " << std::endl;
0537         }
0538         m_out << "]" << std::endl;
0539     }
0540 }
0541 
0542 void JInspector::PrintObjectAncestors(std::string factory_idx, int object_idx) {
0543 
0544     BuildIndices();  // So that we can retrieve the integer index given the factory name/tag pair
0545     auto result = m_factory_index.find(factory_idx);
0546     if (result == m_factory_index.end()) {
0547         m_out << "(Error: Invalid factory name or index)\n";
0548         return;
0549     }
0550     auto fac = const_cast<JFactory*>(result->second.second);
0551     auto objs = fac->GetAs<JObject>();
0552     if ((size_t) object_idx >= objs.size()) {
0553         m_out << "(Error: Object index out of range)" << std::endl;
0554         return;
0555     }
0556     auto obj = objs[object_idx];
0557     m_out << obj->className() << std::endl;
0558     auto ancestors = FindAllAncestors(obj);
0559     if (ancestors.empty()) {
0560          m_out << "(No ancestors found)" << std::endl;
0561          return;
0562     }
0563 
0564     if (m_format == Format::Table) {
0565         JTablePrinter t;
0566         t.AddColumn("Object name");
0567         t.AddColumn("Tag");
0568         t.AddColumn("Factory index", JTablePrinter::Justify::Right);
0569         t.AddColumn("Object index", JTablePrinter::Justify::Right);
0570         t.AddColumn("Object contents");
0571         for (auto ancestor : FindAllAncestors(obj)) {
0572             JFactory* fac;
0573             size_t fac_idx, obj_idx;
0574             std::tie(fac, fac_idx, obj_idx) = LocateObject(*m_event, ancestor);
0575             if (fac == nullptr) {
0576                 m_out << "(Error: Unable to find factory containing object with classname '" << obj->className() << "')" << std::endl;
0577                 continue;
0578             }
0579             JObjectSummary summary;
0580             ancestor->Summarize(summary);
0581 
0582             auto tag = fac->GetTag();
0583             if (tag.empty()) tag = "(no tag)";
0584             std::ostringstream objval;
0585             objval << "{";
0586             for (auto& field : summary.get_fields()) {
0587                 objval << field.name << ": " << field.value << ", ";
0588             }
0589             objval << "}";
0590 
0591             t | fac->GetObjectName() | tag | fac_idx | obj_idx | objval.str();
0592         }
0593         t.Render(m_out);
0594     }
0595     else {
0596         m_out << "[" << std::endl;
0597         for (auto ancestor : FindAllAncestors(obj)) {
0598             JFactory* fac;
0599             size_t fac_idx, obj_idx;
0600             std::tie(fac, fac_idx, obj_idx) = LocateObject(*m_event, ancestor);
0601             if (fac == nullptr) {
0602                 m_out << "(Error: Unable to find factory containing object with classname '" << obj->className() << "')" << std::endl;
0603                 continue;
0604             }
0605             auto tag = fac->GetTag();
0606             if (tag.empty()) tag = "(no tag)";
0607 
0608             m_out << "  " << "{ " << std::endl << "    \"object_name\": \"" << fac->GetObjectName() << "\", ";
0609             if (tag.empty()) {
0610                 m_out << "\"tag\": null, ";
0611             }
0612             else {
0613                 m_out << "\"tag\": \"" << tag << "\", ";
0614             }
0615             m_out << "\"fac_index\": " << fac_idx << ", \"obj_index\": " << obj_idx << "," << std::endl;
0616             m_out << "    \"object_contents\": ";
0617 
0618             JObjectSummary summary;
0619             ancestor->Summarize(summary);
0620             m_out << "{";
0621             for (auto& field : summary.get_fields()) {
0622                 m_out << "\"" << field.name << "\": \"" << field.value << "\", ";
0623             }
0624             m_out << "}" << std::endl;
0625             m_out << "  }, " << std::endl;
0626         }
0627         m_out << "]" << std::endl;
0628     }
0629 }
0630 
0631 void JInspector::Loop() {
0632     bool stay_in_loop = true;
0633     auto app = m_event->GetJApplication();
0634     m_enable_timeout_on_exit = app->IsTimeoutEnabled();
0635     m_enable_ticker_on_exit = app->IsTickerEnabled();
0636     m_event->GetJApplication()->SetTicker( false );
0637     m_event->GetJApplication()->SetTimeoutEnabled( false );
0638     m_out << std::endl;
0639     m_out << "--------------------------------------------------------------------------------------" << std::endl;
0640     m_out << "Welcome to JANA's interactive inspector! Type `Help` or `h` to see available commands." << std::endl;
0641     m_out << "--------------------------------------------------------------------------------------" << std::endl;
0642     PrintEvent();
0643     while (stay_in_loop) {
0644         std::string user_input;
0645         m_out << std::endl << "JANA: "; m_out.flush();
0646         // Obtain a single line
0647         std::getline(m_in, user_input);
0648         // Split into tokens
0649         std::stringstream ss(user_input);
0650         std::string token;
0651         ss >> token;
0652         std::vector<std::string> args;
0653         std::string arg;
0654         while (ss >> arg) {
0655             args.push_back(arg);
0656         }
0657         try {
0658             if (token == "PrintEvent" || token == "pe") {
0659                 PrintEvent();
0660             }
0661             else if ((token == "PrintFactories" || token == "pf") && args.empty()) {
0662                 PrintFactories(0);
0663             }
0664             else if ((token == "PrintFactories" || token == "pf") && args.size() == 1) {
0665                 PrintFactories(std::stoi(args[0]));
0666             }
0667             else if ((token == "PrintFactoryDetails" || token == "pfd") && (args.size() == 1)) {
0668                 PrintFactoryDetails(args[0]);
0669             }
0670             else if ((token == "PrintObjects" || token == "po") && (args.size() == 1)) {
0671                 PrintObjects(args[0]);
0672             }
0673             else if ((token == "PrintObject" || token == "po") && (args.size() == 2)) {
0674                 PrintObject(args[0], std::stoi(args[1]));
0675             }
0676             else if ((token == "PrintFactoryParents" || token == "pfp") && (args.size() == 1)) {
0677                 PrintFactoryParents(args[0]);
0678             }
0679             else if ((token == "PrintObjectParents" || token == "pop") && (args.size() == 2)) {
0680                 PrintObjectParents(args[0], std::stoi(args[1]));
0681             }
0682             else if ((token == "PrintObjectAncestors" || token == "poa") && (args.size() == 2)) {
0683                 PrintObjectAncestors(args[0], std::stoi(args[1]));
0684             }
0685             else if (token == "ViewAsTable" || token == "vt") {
0686                 m_format = Format::Table;
0687                 m_out << "(Switching to table view mode)" << std::endl;
0688             }
0689             else if (token == "ViewAsJson" || token == "vj") {
0690                 m_format = Format::Json;
0691                 m_out << "(Switching to JSON view mode)" << std::endl;
0692             }
0693             else if (token == "Continue" || token == "c") {
0694                 stay_in_loop = false;
0695             }
0696             else if (token == "Exit" || token == "x") {
0697                 stay_in_loop = false;
0698             }
0699             else if (token == "Help" || token == "h") {
0700                 PrintHelp();
0701             }
0702             else if (token == "") {
0703                 // Do nothing
0704             }
0705             else {
0706                 m_out << "(Error: Unrecognized command, or wrong argument count)" << std::endl;
0707                 PrintHelp();
0708             }
0709 
0710         }
0711         catch (JException& ex) {
0712             m_out << "(JException: Maybe you tried to print out objects that are not JObjects)" << std::endl;
0713         }
0714         catch (std::invalid_argument&) {
0715             m_out << "(Parse error: Maybe an argument needs to be an int)" << std::endl;
0716         }
0717         catch (...) {
0718             m_out << "(Unknown error)" << std::endl;
0719         }
0720     }
0721 
0722     if (m_enable_ticker_on_exit) {
0723         m_event->GetJApplication()->SetTicker( true );
0724     }
0725     if (m_enable_timeout_on_exit) {
0726         m_event->GetJApplication()->SetTimeoutEnabled( true );
0727     }
0728 }